home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / C / Applications / POV-Ray 3.0.2 / src / SOURCE / LIGHTING.C < prev    next >
Encoding:
C/C++ Source or Header  |  1996-09-19  |  82.9 KB  |  3,355 lines  |  [TEXT/CWIE]

  1. /****************************************************************************
  2. *                   lighting.c
  3. *
  4. *  This module calculates lighting properties like ambient, diffuse, specular,
  5. *  reflection, refraction, etc.
  6. *
  7. *  from Persistence of Vision(tm) Ray Tracer
  8. *  Copyright 1996 Persistence of Vision Team
  9. *---------------------------------------------------------------------------
  10. *  NOTICE: This source code file is provided so that users may experiment
  11. *  with enhancements to POV-Ray and to port the software to platforms other
  12. *  than those supported by the POV-Ray Team.  There are strict rules under
  13. *  which you are permitted to use this file.  The rules are in the file
  14. *  named POVLEGAL.DOC which should be distributed with this file. If
  15. *  POVLEGAL.DOC is not available or for more info please contact the POV-Ray
  16. *  Team Coordinator by leaving a message in CompuServe's Graphics Developer's
  17. *  Forum.  The latest version of POV-Ray may be found there as well.
  18. *
  19. * This program is based on the popular DKB raytracer version 2.12.
  20. * DKBTrace was originally written by David K. Buck.
  21. * DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins.
  22. *
  23. *****************************************************************************/
  24.  
  25. #include "frame.h"
  26. #include "vector.h"
  27. #include "povproto.h"
  28. #include "blob.h"
  29. #include "bbox.h"
  30. #include "colour.h"
  31. #include "halos.h"
  32. #include "image.h"
  33. #include "lbuffer.h"
  34. #include "lighting.h"
  35. #include "mesh.h"
  36. #include "normal.h"
  37. #include "objects.h"
  38. #include "octree.h"
  39. #include "pattern.h"  /* [CEY 10/94] */
  40. #include "pigment.h"
  41. #include "povray.h"
  42. #include "radiosit.h"
  43. #include "ray.h"
  44. #include "render.h"
  45. #include "texture.h"
  46.  
  47.  
  48.  
  49. /*****************************************************************************
  50. * Local preprocessor defines
  51. ******************************************************************************/
  52.  
  53. #define BLACK_LEVEL 0.003
  54.  
  55. /*
  56.  * "Small_Tolerance" is just too tight for higher order polynomial equations.
  57.  * this value should probably be a variable of some sort, but for now just
  58.  * use a reasonably small value.  If people render real small objects real
  59.  * close to each other then there may be some shading problems.  Otherwise
  60.  * having SHADOW_TOLERANCE as large as this won't affect images.
  61.  */
  62.  
  63. #define SHADOW_TOLERANCE 1.0e-3
  64.  
  65. /* Number of inital entries in the texture and weight list. */
  66.  
  67. #define NUMBER_OF_ENTRIES 16
  68.  
  69.  
  70.  
  71. /*****************************************************************************
  72. * Local typedefs
  73. ******************************************************************************/
  74.  
  75. /*
  76.  * List to store light colours during shadow testing
  77.  * to avoid repeated testing with layered textures.
  78.  */
  79.  
  80. typedef struct Light_Tested_Struct LIGHT_TESTED;
  81.  
  82. struct Light_Tested_Struct
  83. {
  84.   int    Tested;
  85.   COLOUR Colour;
  86. };
  87.  
  88.  
  89.  
  90. /*****************************************************************************
  91. * Local variables
  92. ******************************************************************************/
  93.  
  94. static LIGHT_TESTED *Light_List;
  95. static TEXTURE **Texture_List;
  96. static DBL *Weight_List;
  97.  
  98. static int Number_Of_Textures_And_Weights;
  99.  
  100.  
  101.  
  102. /*****************************************************************************
  103. * Static functions
  104. ******************************************************************************/
  105.  
  106. static void block_area_light PARAMS((LIGHT_SOURCE *Light_Source,
  107.   DBL *Light_Source_Depth, RAY *Light_Source_Ray, RAY *Eye_Ray,
  108.   VECTOR IPoint, COLOUR Light_Colour, int u1, int v1, int u2, int v2, int Level));
  109.  
  110. static void block_point_light PARAMS((LIGHT_SOURCE *Light_Source,
  111.   DBL *Light_Source_Depth, RAY *Light_Source_Ray, COLOUR Light_Colour));
  112.  
  113. static void block_point_light_LBuffer PARAMS((LIGHT_SOURCE *Light_Source,
  114.   DBL *Light_Source_Depth, RAY *Light_Source_Ray, COLOUR Light_Colour));
  115.  
  116. static void do_light PARAMS((LIGHT_SOURCE *Light_Source,
  117.   DBL *Light_Source_Depth, RAY *Light_Source_Ray, RAY *Eye_Ray, VECTOR IPoint,
  118.   COLOUR Light_Colour));
  119.  
  120. static int do_blocking PARAMS((INTERSECTION *Local_Intersection,
  121.   RAY *Light_Source_Ray, COLOUR Light_Colour, ISTACK *Local_Stack));
  122.  
  123. static void do_phong PARAMS((FINISH *Finish, RAY *Light_Source_Ray,
  124.   VECTOR Eye, VECTOR Layer_Normal, COLOUR Colour, COLOUR Light_Colour,
  125.   COLOUR Layer_Texture_Colour));
  126.  
  127. static void do_specular PARAMS((FINISH *Finish, RAY *Light_Source_Ray,
  128.   VECTOR REye, VECTOR Layer_Normal, COLOUR Colour, COLOUR Light_Colour,
  129.   COLOUR Layer_Pigment_Colour));
  130.  
  131. static void do_diffuse PARAMS((FINISH *Finish, RAY *Light_Source_Ray,
  132.   VECTOR Layer_Normal, COLOUR Colour, COLOUR Light_Colour,
  133.   COLOUR Layer_Pigment_Colour, DBL Attenuation));
  134.  
  135. static void do_irid PARAMS((FINISH *Finish, RAY *Light_Source_Ray,
  136.   VECTOR Layer_Normal, VECTOR IPoint, COLOUR Colour));
  137.  
  138. static void Diffuse PARAMS((FINISH *Finish, VECTOR IPoint, RAY *Eye, VECTOR Layer_Normal,
  139.   COLOUR Layer_Pigment_Colour, COLOUR Colour,DBL Attenuation, OBJECT *Object));
  140.  
  141. static void Reflect PARAMS((RGB Reflection, VECTOR IPoint, RAY *Ray, VECTOR Layer_Normal, COLOUR Colour, DBL Weight));
  142.  
  143. static void Refract PARAMS((OBJECT *Object, TEXTURE *Texture, VECTOR IPoint,
  144.   RAY *Ray, VECTOR Layer_Normal, COLOUR Colour, DBL Weight));
  145.  
  146. static void filter_shadow_ray PARAMS((INTERSECTION *Ray_Intersection,
  147.   RAY *Light_Source_Ray, COLOUR Colour));
  148.  
  149. static int create_texture_list PARAMS((INTERSECTION *Ray_Intersection));
  150.  
  151. static void do_texture_map PARAMS((COLOUR Result_Colour,
  152.   TEXTURE *Texture, VECTOR IPoint, VECTOR Raw_Normal, RAY *Ray, DBL Weight,
  153.   INTERSECTION *Ray_Intersection, int Shadow_Flag));
  154.  
  155. static void average_textures PARAMS((COLOUR Result_Colour,
  156.   TEXTURE *Texture, VECTOR IPoint, VECTOR Raw_Normal, RAY *Ray, DBL Weight,
  157.   INTERSECTION *Ray_Intersection, int Shadow_Flag));
  158.  
  159. static void compute_lighted_texture PARAMS((COLOUR Result_Colour,
  160.   TEXTURE *Texture, VECTOR IPoint, VECTOR Raw_Normal, RAY *Ray, DBL Weight,
  161.   INTERSECTION *Ray_Intersection));
  162.  
  163. static void compute_shadow_texture PARAMS((COLOUR Filter_Colour,
  164.   TEXTURE *Texture, VECTOR IPoint, VECTOR Raw_Normal, RAY *Ray,
  165.   INTERSECTION *Ray_Intersection));
  166.  
  167. static void block_light_source PARAMS((LIGHT_SOURCE *Light,
  168.   DBL Depth, RAY *Light_Source_Ray, RAY *Eye_Ray, VECTOR P, COLOUR Colour));
  169.  
  170. static void do_light_ray_atmosphere PARAMS((RAY *Light_Source_Ray,
  171.   INTERSECTION *Ray_Intersection, TEXTURE *Texture, COLOUR Colour, int Valid_Object));
  172.  
  173.  
  174.  
  175. /*****************************************************************************
  176. *
  177. * FUNCTION
  178. *
  179. *   Initialize_Lighting_Code
  180. *
  181. * INPUT
  182. *
  183. * OUTPUT
  184. *   
  185. * RETURNS
  186. *   
  187. * AUTHOR
  188. *
  189. *   Dieter Bayer
  190. *   
  191. * DESCRIPTION
  192. *
  193. *   Allocate lists needed during lighting calculations.
  194. *
  195. * CHANGES
  196. *
  197. *   Sep 1994 : Creation.
  198. *
  199. *   Okt 1994 : Added initialization of Light_List and test if there are
  200. *              any light sources in the scene. [DB]
  201. *
  202. ******************************************************************************/
  203.  
  204. void Initialize_Lighting_Code()
  205. {
  206.   int i;
  207.  
  208.   Light_List = NULL;
  209.   Texture_List = NULL;
  210.   Weight_List  = NULL;
  211.  
  212.   /* Allocate memory for light list. */
  213.  
  214.   if (Frame.Number_Of_Light_Sources > 0)
  215.   {
  216.     Light_List = (LIGHT_TESTED *)POV_MALLOC(Frame.Number_Of_Light_Sources*sizeof(LIGHT_TESTED), "temporary light list");
  217.  
  218.     for (i = 0; i < Frame.Number_Of_Light_Sources; i++)
  219.     {
  220.       Light_List[i].Tested = FALSE;
  221.  
  222.       Make_ColourA(Light_List[i].Colour, 0.0, 0.0, 0.0, 0.0, 0.0);
  223.     }
  224.   }
  225.  
  226.   /* Allocate memory for texture and weight list. */
  227.  
  228.   Number_Of_Textures_And_Weights = NUMBER_OF_ENTRIES;
  229.  
  230.   Texture_List = (TEXTURE **)POV_MALLOC(Number_Of_Textures_And_Weights*sizeof(TEXTURE *), "texture list");
  231.  
  232.   Weight_List = (DBL *)POV_MALLOC(Number_Of_Textures_And_Weights*sizeof(DBL), "weight list");
  233. }
  234.  
  235.  
  236.  
  237. /*****************************************************************************
  238. *
  239. * FUNCTION
  240. *
  241. *   Reinitialize_Lighting_Code
  242. *
  243. * INPUT
  244. *
  245. *   Number_Of_Entries - New number of entries in the texture/weight lists
  246. *   
  247. * OUTPUT
  248. *
  249. * RETURNS
  250. *   
  251. * AUTHOR
  252. *
  253. *   Dieter Bayer
  254. *   
  255. * DESCRIPTION
  256. *
  257. *   Resize variable lists needed during lighting calculation.
  258. *
  259. * CHANGES
  260. *
  261. *   Jul 1995 : Creation.
  262. *
  263. *   Mar 1996 : We have to pass pointers to the lists to resize because during
  264. *              resizing the pointers to the lists change and thus the calling
  265. *              functions does not longer know where the lists are if the
  266. *              pointers to the lists where passed to it using arguments. [DB]
  267. *
  268. ******************************************************************************/
  269.  
  270. void Reinitialize_Lighting_Code(Number_Of_Entries, Textures, Weights)
  271. int Number_Of_Entries;
  272. TEXTURE ***Textures;
  273. DBL **Weights;
  274. {
  275.   if (Number_Of_Entries > Number_Of_Textures_And_Weights)
  276.   {
  277.     if (Number_Of_Entries >= INT_MAX / 2)
  278.     {
  279.       Error("Too many entries in texture and weight lists.\n");
  280.     }
  281.  
  282.     Number_Of_Textures_And_Weights = Number_Of_Entries;
  283.  
  284.     Texture_List = (TEXTURE **)POV_REALLOC(Texture_List, Number_Of_Textures_And_Weights*sizeof(TEXTURE *), "texture list");
  285.  
  286.     Weight_List = (DBL *)POV_REALLOC(Weight_List, Number_Of_Textures_And_Weights*sizeof(DBL), "weight list");
  287.  
  288.     *Textures = Texture_List;
  289.     *Weights  = Weight_List;
  290.   }
  291. }
  292.  
  293.  
  294.  
  295. /*****************************************************************************
  296. *
  297. * FUNCTION
  298. *
  299. *   Deinitialize_Lighting_Code
  300. *
  301. * INPUT
  302. *   
  303. * OUTPUT
  304. *   
  305. * RETURNS
  306. *   
  307. * AUTHOR
  308. *
  309. *   Dieter Bayer
  310. *   
  311. * DESCRIPTION
  312. *
  313. *   Destroy all lists needed during lighting calculation.
  314. *
  315. * CHANGES
  316. *
  317. *   Sep 1994 : Creation.
  318. *
  319. *   Jul 1995 : Added code to free local texture and weight lists. [DB]
  320. *
  321. ******************************************************************************/
  322.  
  323. void Deinitialize_Lighting_Code()
  324. {
  325.   if (Light_List != NULL)
  326.   {
  327.     POV_FREE(Light_List);
  328.   }
  329.  
  330.   if (Texture_List != NULL)
  331.   {
  332.     POV_FREE(Texture_List);
  333.   }
  334.  
  335.   if (Weight_List != NULL)
  336.   {
  337.     POV_FREE(Weight_List);
  338.   }
  339.  
  340.   Light_List   = NULL;
  341.   Texture_List = NULL;
  342.   Weight_List  = NULL;
  343. }
  344.  
  345.  
  346.  
  347. /*****************************************************************************
  348. *
  349. * FUNCTION
  350. *
  351. *   Determine_Apparent_Colour
  352. *
  353. * INPUT
  354. *
  355. *   Ray_Intersection - info on where ray hit & object it hit
  356. *   Ray              - the ray from which object is seen
  357. *   Weight           - Automatic depth control value
  358. *
  359. * OUTPUT
  360. *
  361. *   Colour           - resulting color is added to given color. The RGB
  362. *                      components are significant. The transmittance channel
  363. *                      is used as an alpha channel.
  364. *
  365. * RETURNS
  366. *
  367. * AUTHOR
  368. *
  369. *   POV-Ray Team
  370. *
  371. * DESCRIPTION
  372. *
  373. *   Given an intersection point, a ray, add that point's visible color
  374. *   to the given colour and return it.  This routine just does preliminary
  375. *   initializations and calls to set up the multi-texture blob list if any.
  376. *   Then it calls do_texture_map which in turn calls compute_lighted_texture
  377. *   to do the actual lighting calculations.  These functions were seperated
  378. *   from this function because do_texture_map may need to call itself
  379. *   recursively.
  380. *
  381. * CHANGES
  382. *
  383. *   Sep 1994 : Code for multi-textured blobs added. [DB]
  384. *
  385. *   Nov 1994 : Moved calls to Fog and Rainbow into tracing functions. [DB]
  386. *
  387. *   Jan 1995 : Moved much of code to do_texture_map and
  388. *              compute_lighted_texture [CEY]
  389. *
  390. *   Jul 1995 : Added code to support alpha channel. [DB]
  391. *
  392. *   Mar 1996 : Fixed severe bug (weight and texture lists were not saved) [DB]
  393. *
  394. ******************************************************************************/
  395.  
  396. void Determine_Apparent_Colour(Ray_Intersection, Colour, Ray, Weight)
  397. INTERSECTION *Ray_Intersection;
  398. COLOUR Colour;
  399. RAY *Ray;
  400. DBL Weight;
  401. {
  402.   int i, Texture_Count;
  403.   size_t savelights_size, save_tw_size;
  404.   DBL *save_Weights = NULL;
  405.   COLOUR C1;
  406.   VECTOR Raw_Normal;
  407.   VECTOR IPoint;
  408.   TEXTURE *Texture, **save_Textures = NULL;
  409.   LIGHT_TESTED *savelights = NULL;
  410.  
  411.   Assign_Vector(IPoint,Ray_Intersection->IPoint);
  412.  
  413.   /*
  414.    * Save existing light list if any. If we are not top level in recursion
  415.    * depth, this information may be reused by upper level of trace.
  416.    */
  417.  
  418.   savelights_size = (size_t)(Frame.Number_Of_Light_Sources*sizeof(LIGHT_TESTED));
  419.  
  420.   if (savelights_size > 0)
  421.   {
  422.     savelights = (LIGHT_TESTED *)POV_MALLOC(savelights_size, "Light list stack");
  423.  
  424.     memcpy(savelights, Light_List, savelights_size);
  425.   }
  426.  
  427.   /* Init light list. */
  428.  
  429.   for (i = 0; i < Frame.Number_Of_Light_Sources; i++)
  430.   {
  431.     Light_List[i].Tested = FALSE;
  432.   }
  433.  
  434.   /* Get the normal to the surface */
  435.  
  436.   Normal(Raw_Normal, Ray_Intersection->Object, Ray_Intersection);
  437.  
  438.   /*
  439.    * Save texture and weight lists.
  440.    */
  441.  
  442.   save_tw_size = (size_t)Number_Of_Textures_And_Weights;
  443.  
  444.   if (save_tw_size > 0)
  445.   {
  446.     save_Weights = (DBL *)POV_MALLOC(save_tw_size * sizeof(DBL), "Weight list stack");
  447.  
  448.     memcpy(save_Weights, Weight_List, save_tw_size * sizeof(DBL));
  449.  
  450.     save_Textures = (TEXTURE **)POV_MALLOC(save_tw_size * sizeof(TEXTURE *), "Weight list stack");
  451.  
  452.     memcpy(save_Textures, Texture_List, save_tw_size * sizeof(TEXTURE *));
  453.   }
  454.  
  455.   /* Get texture list and weights. */
  456.  
  457.   Texture_Count = create_texture_list (Ray_Intersection);
  458.  
  459.   /*
  460.    * Now, we perform the lighting calculations by stepping through
  461.    * the list of textures and summing the weighted color.
  462.    */
  463.  
  464.   for (i = 0; i < Texture_Count; i++)
  465.   {
  466.     /* If contribution of this texture is neglectable skip ahead. */
  467.  
  468.     if (Weight_List[i] < BLACK_LEVEL)
  469.     {
  470.       continue;
  471.     }
  472.  
  473.     Texture = Texture_List[i];
  474.  
  475.     do_texture_map(C1, Texture, IPoint, Raw_Normal, Ray, Weight, Ray_Intersection, FALSE);
  476.  
  477.     Colour[RED]   += Weight_List[i] * C1[RED];
  478.     Colour[GREEN] += Weight_List[i] * C1[GREEN];
  479.     Colour[BLUE]  += Weight_List[i] * C1[BLUE];
  480.  
  481.     /* Use transmittance value for alpha channel support. [DB] */
  482.  
  483. /*
  484.     Colour[TRANSM]  += Weight_List[i] * C1[TRANSM];
  485. */
  486.     Colour[TRANSM] *= C1[TRANSM];
  487.   }
  488.  
  489.   /* Restore the light list to its original form */
  490.  
  491.   if (savelights_size > 0)
  492.   {
  493.     memcpy(Light_List, savelights, savelights_size);
  494.  
  495.     POV_FREE(savelights);
  496.   }
  497.  
  498.   /* Restore the weight and texture list. */
  499.  
  500.   if (save_tw_size > 0)
  501.   {
  502.     memcpy(Weight_List, save_Weights, save_tw_size * sizeof(DBL));
  503.     memcpy(Texture_List, save_Textures, save_tw_size * sizeof(TEXTURE *));
  504.  
  505.     POV_FREE(save_Weights);
  506.     POV_FREE(save_Textures);
  507.   }
  508. }
  509.  
  510.  
  511.  
  512. /*****************************************************************************
  513. *
  514. * FUNCTION
  515. *
  516. *   Test_Shadow
  517. *
  518. * INPUT
  519. *
  520. *   Light            - Light source
  521. *   P                - Point to test
  522. *
  523. * OUTPUT
  524. *
  525. *   Depth            - Distance to light source
  526. *   Light_Source_Ray - Light ray pointing towards the light source
  527. *   Eye_Ray          - Current viewing ray
  528. *   Colour           - Light color reaching point P
  529. *
  530. * RETURNS
  531. *
  532. *   int - TRUE if point lies in shadow
  533. *
  534. * AUTHOR
  535. *
  536. *   Dieter Bayer
  537. *
  538. * DESCRIPTION
  539. *
  540. *   Test if a given point is in shadow in respect to the given light source.
  541. *
  542. *   The viewing ray is used to initialize the ray containers of the
  543. *   light source ray.
  544. *
  545. * CHANGES
  546. *
  547. *   Nov 1994 : Creation.
  548. *
  549. ******************************************************************************/
  550.  
  551. int Test_Shadow(Light, Depth, Light_Source_Ray, Eye_Ray, P, Colour)
  552. LIGHT_SOURCE *Light;
  553. DBL *Depth;
  554. RAY *Light_Source_Ray, *Eye_Ray;
  555. VECTOR P;
  556. COLOUR Colour;
  557. {
  558.   do_light(Light, Depth, Light_Source_Ray, Eye_Ray, P, Colour);
  559.  
  560.   /*
  561.    * There's no need to test for shadows if no light
  562.    * is coming from the light source.
  563.    */
  564.  
  565.   if ((Colour[X] < BLACK_LEVEL) && (Colour[Y] < BLACK_LEVEL) && (Colour[Z] < BLACK_LEVEL))
  566.   {
  567.     return(TRUE);
  568.   }
  569.   else
  570.   {
  571.     /* Test for shadows. */
  572.  
  573.     if ((opts.Quality_Flags & Q_SHADOW) && (Light->Light_Type != FILL_LIGHT_SOURCE))
  574.     {
  575.       block_light_source(Light, *Depth, Light_Source_Ray, Eye_Ray, P, Colour);
  576.  
  577.       if ((Colour[X] < BLACK_LEVEL) && (Colour[Y] < BLACK_LEVEL) && (Colour[Z] < BLACK_LEVEL))
  578.       {
  579.         return(TRUE);
  580.       }
  581.     }
  582.   }
  583.  
  584.   return(FALSE);
  585. }
  586.  
  587.  
  588.  
  589. /*****************************************************************************
  590. *
  591. * FUNCTION
  592. *
  593. *   block_point_light_LBuffer
  594. *
  595. * INPUT
  596. *
  597. *   Light_Source       - Light source to test
  598. *
  599. * OUTPUT
  600. *
  601. *   Light_Source_Depth - (Remaining) distance to the light source
  602. *   Light_Source_Ray   - (Remaining) ray to the light source
  603. *   Colour             - Color reaching initial point from light source
  604. *
  605. * RETURNS
  606. *
  607. * AUTHOR
  608. *
  609. *   Dieter Bayer
  610. *
  611. * DESCRIPTION
  612. *
  613. *   Determine how much light from the given light source arrives at the
  614. *   given point (starting point of the light source ray). The light
  615. *   is blocked by solid objects and/or attenuated by translucent objects.
  616. *
  617. *   Note that both the distance to the light source and the light source
  618. *   ray are modified. Thus after a call to this function one knows
  619. *   how much distance remains to the light source and where the last
  620. *   intersection point with a translucent object was (starting point
  621. *   of light source ray after the call).
  622. *
  623. *   This function uses the light buffer to speed up shadow calculation.
  624. *
  625. * CHANGES
  626. *
  627. *   Jul 1994 : Creation.
  628. *
  629. ******************************************************************************/
  630.  
  631. static void block_point_light_LBuffer(Light_Source, Light_Source_Depth, Light_Source_Ray, Light_Colour)
  632. LIGHT_SOURCE *Light_Source;
  633. DBL *Light_Source_Depth;
  634. RAY *Light_Source_Ray;
  635. COLOUR Light_Colour;
  636. {
  637.   int Quit_Looking, Not_Found_Shadow, Cache_Me;
  638.   int u, v, axis;
  639.   DBL ax, ay, az;
  640.   VECTOR V1;
  641.   OBJECT *Blocking_Object;
  642.   ISTACK *Local_Stack;
  643.   INTERSECTION *Local_Intersection, Bounded_Intersection;
  644.  
  645.   Local_Stack = open_istack();
  646.  
  647.   Quit_Looking = FALSE;
  648.  
  649.   /* First test the cached object (don't cache semi-transparent objects). */
  650.  
  651.   if (Light_Source->Shadow_Cached_Object != NULL)
  652.   {
  653.     Increase_Counter(stats[Shadow_Ray_Tests]);
  654.  
  655.     if (Ray_In_Bound(Light_Source_Ray, Light_Source->Shadow_Cached_Object->Bound))
  656.     {
  657.       if (All_Intersections(Light_Source->Shadow_Cached_Object, Light_Source_Ray, Local_Stack))
  658.       {
  659.         while ((Local_Intersection=pop_entry(Local_Stack)) != NULL)
  660.         {
  661.           if ((!Test_Flag(Local_Intersection->Object, NO_SHADOW_FLAG)) &&
  662.               (Local_Intersection->Depth < *Light_Source_Depth-SHADOW_TOLERANCE) &&
  663.               (Local_Intersection->Depth > SHADOW_TOLERANCE))
  664.           {
  665.             if (do_blocking(Local_Intersection, Light_Source_Ray, Light_Colour, Local_Stack))
  666.             {
  667.               Quit_Looking = TRUE;
  668.  
  669.               Increase_Counter(stats[Shadow_Cache_Hits]);
  670.  
  671.               break;
  672.             }
  673.           }
  674.         }
  675.       }
  676.     }
  677.  
  678.     /* Exit if the cached object was hit. */
  679.  
  680.     if (Quit_Looking)
  681.     {
  682.       close_istack(Local_Stack);
  683.  
  684.       return;
  685.     }
  686.   }
  687.  
  688.   /*
  689.    * Determine the side and the coordinates at which the ray
  690.    * pierces the cube enclosing the light source.
  691.    */
  692.  
  693.   V1[X] = -Light_Source_Ray->Direction[X];
  694.   V1[Y] = -Light_Source_Ray->Direction[Y];
  695.   V1[Z] = -Light_Source_Ray->Direction[Z];
  696.  
  697.   ax = fabs(V1[X]);
  698.   ay = fabs(V1[Y]);
  699.   az = fabs(V1[Z]);
  700.  
  701.   if ((ax>ay) && (ax>az))
  702.   {
  703.     if (V1[X]>0.0)
  704.     {
  705.       axis = XaxisP;
  706.     }
  707.     else
  708.     {
  709.       axis = XaxisM;
  710.     }
  711.  
  712.     u = (int)(MAX_BUFFER_ENTRY * V1[Y]/ax);
  713.     v = (int)(MAX_BUFFER_ENTRY * V1[Z]/ax);
  714.   }
  715.   else
  716.   {
  717.     if (ay>az)
  718.     {
  719.       if (V1[Y]>0.0)
  720.       {
  721.         axis = YaxisP;
  722.       }
  723.       else
  724.       {
  725.         axis = YaxisM;
  726.       }
  727.  
  728.       u = (int)(MAX_BUFFER_ENTRY * V1[X]/ay);
  729.       v = (int)(MAX_BUFFER_ENTRY * V1[Z]/ay);
  730.     }
  731.     else
  732.     {
  733.       if (V1[Z]>0.0)
  734.       {
  735.         axis = ZaxisP;
  736.       }
  737.       else
  738.       {
  739.         axis = ZaxisM;
  740.       }
  741.  
  742.       u = (int)(MAX_BUFFER_ENTRY * V1[X]/az);
  743.       v = (int)(MAX_BUFFER_ENTRY * V1[Y]/az);
  744.     }
  745.   }
  746.  
  747.   /* If there are no objects in the direction of the ray we can exit. */
  748.  
  749.   if (Light_Source->Light_Buffer[axis] == NULL)
  750.   {
  751.     close_istack(Local_Stack);
  752.  
  753.     return;
  754.   }
  755.  
  756.   /* Look for shadows. */
  757.  
  758.   Not_Found_Shadow = TRUE;
  759.  
  760.   Cache_Me = FALSE;
  761.  
  762.   while (!Quit_Looking)
  763.   {
  764.     Increase_Counter(stats[Shadow_Ray_Tests]);
  765.  
  766.     Bounded_Intersection.Depth = *Light_Source_Depth;
  767.  
  768.     if (Intersect_Light_Tree(Light_Source_Ray, Light_Source->Light_Buffer[axis], u, v, &Bounded_Intersection, &Blocking_Object))
  769.     {
  770.       if (Bounded_Intersection.Depth > *Light_Source_Depth)
  771.       {
  772.         /* Intersection was beyond the light. */
  773.  
  774.         break;
  775.       }
  776.  
  777.       if (!Test_Flag(Bounded_Intersection.Object, NO_SHADOW_FLAG))
  778.       {
  779.         if (Blocking_Object != Light_Source->Shadow_Cached_Object)
  780.         {
  781.           Increase_Counter(stats[Shadow_Rays_Succeeded]);
  782.  
  783.           filter_shadow_ray(&Bounded_Intersection, Light_Source_Ray, Light_Colour);
  784.  
  785.           if ((fabs(Light_Colour[RED])   < BLACK_LEVEL) &&
  786.               (fabs(Light_Colour[GREEN]) < BLACK_LEVEL) &&
  787.               (fabs(Light_Colour[BLUE])  < BLACK_LEVEL) &&
  788.               (Test_Flag(Blocking_Object, OPAQUE_FLAG)))
  789.           {
  790.             Cache_Me = Not_Found_Shadow;
  791.  
  792.             break; /* from while */
  793.           }
  794.         }
  795.       }
  796.  
  797.       /* Move the ray to the point of intersection, plus some */
  798.  
  799.       *Light_Source_Depth -= Bounded_Intersection.Depth;
  800.  
  801.       Assign_Vector(Light_Source_Ray->Initial, Bounded_Intersection.IPoint);
  802.  
  803.       Not_Found_Shadow = FALSE;
  804.     }
  805.     else
  806.     {
  807.       /* No intersections in the direction of the ray. */
  808.  
  809.       break;
  810.     }
  811.   }
  812.  
  813.   if (Cache_Me)
  814.   {
  815.     Light_Source->Shadow_Cached_Object = Blocking_Object;
  816.   }
  817.  
  818.   close_istack(Local_Stack);
  819. }
  820.  
  821.  
  822.  
  823. /*****************************************************************************
  824. *
  825. * FUNCTION
  826. *
  827. *   block_point_light
  828. *
  829. * INPUT
  830. *
  831. *   Light_Source       - Light source to test
  832. *   Eye_Ray            - Current viewing ray
  833. *
  834. * OUTPUT
  835. *
  836. *   Light_Source_Depth - (Remaining) distance to the light source
  837. *   Light_Source_Ray   - (Remaining) ray to the light source
  838. *   Colour             - Color reaching initial point from light source
  839. *
  840. * RETURNS
  841. *
  842. * AUTHOR
  843. *
  844. *   POV-Ray Team
  845. *
  846. * DESCRIPTION
  847. *
  848. *   See block_point_light_LBuffer for a description.
  849. *
  850. *   This function uses the hierarchical bounding box volume to
  851. *   speed up shadow testing.
  852. *
  853. * CHANGES
  854. *
  855. *   -
  856. *
  857. ******************************************************************************/
  858.  
  859. static void block_point_light (Light_Source, Light_Source_Depth, Light_Source_Ray, Light_Colour)
  860. LIGHT_SOURCE *Light_Source;
  861. DBL *Light_Source_Depth;
  862. RAY *Light_Source_Ray;
  863. COLOUR Light_Colour;
  864. {
  865.   OBJECT *Blocking_Object;
  866.   int Quit_Looking, Not_Found_Shadow, Cache_Me, Maybe_Found;
  867.   INTERSECTION *Local_Intersection, Bounded_Intersection, Temp_Intersection;
  868.   ISTACK *Local_Stack;
  869.  
  870.   Local_Stack = open_istack ();
  871.  
  872.   Quit_Looking = FALSE;
  873.  
  874.   /* First test the cached object (don't cache semi-transparent objects). */
  875.  
  876.   if (Light_Source->Shadow_Cached_Object != NULL)
  877.   {
  878.     Increase_Counter(stats[Shadow_Ray_Tests]);
  879.  
  880.     if (Ray_In_Bound(Light_Source_Ray, Light_Source->Shadow_Cached_Object->Bound))
  881.     {
  882.       if (All_Intersections(Light_Source->Shadow_Cached_Object, Light_Source_Ray, Local_Stack))
  883.       {
  884.         while ((Local_Intersection = pop_entry(Local_Stack)) != NULL)
  885.         {
  886.           if ((!Test_Flag(Local_Intersection->Object, NO_SHADOW_FLAG)) &&
  887.               (Local_Intersection->Depth < *Light_Source_Depth-SHADOW_TOLERANCE) &&
  888.               (Local_Intersection->Depth > SHADOW_TOLERANCE))
  889.           {
  890.             if (do_blocking(Local_Intersection, Light_Source_Ray, Light_Colour, Local_Stack))
  891.             {
  892.               Quit_Looking = TRUE;
  893.  
  894.               Increase_Counter(stats[Shadow_Cache_Hits]);
  895.  
  896.               break;
  897.             }
  898.           }
  899.         }
  900.       }
  901.     }
  902.  
  903.     if (Quit_Looking)
  904.     {
  905.       close_istack (Local_Stack);
  906.  
  907.       return;
  908.     }
  909.   }
  910.  
  911.   /* Look for shadows. */
  912.  
  913.   Not_Found_Shadow = TRUE;
  914.  
  915.   Cache_Me = FALSE;
  916.  
  917.   if (!opts.Use_Slabs)
  918.   {
  919.     while (!Quit_Looking)
  920.     {
  921.       /* Use brute force method to get shadows. */
  922.  
  923.       Maybe_Found = FALSE;
  924.  
  925.       Bounded_Intersection.Depth = *Light_Source_Depth;
  926.  
  927.       for (Blocking_Object = Frame.Objects; Blocking_Object != NULL; Blocking_Object = Blocking_Object->Sibling)
  928.       {
  929.         if (Blocking_Object != Light_Source->Shadow_Cached_Object)
  930.         {
  931.           if (!Test_Flag(Blocking_Object, NO_SHADOW_FLAG))
  932.           {
  933.             Increase_Counter(stats[Shadow_Ray_Tests]);
  934.  
  935.             if (Intersection(&Temp_Intersection, Blocking_Object, Light_Source_Ray))
  936.             {
  937.               if (Temp_Intersection.Depth < Bounded_Intersection.Depth)
  938.               {
  939.                 Maybe_Found = TRUE;
  940.  
  941.                 Bounded_Intersection = Temp_Intersection;
  942.               }
  943.             }
  944.           }
  945.         }
  946.       }
  947.  
  948.       if (Maybe_Found)
  949.       {
  950.         Increase_Counter(stats[Shadow_Rays_Succeeded]);
  951.  
  952.         filter_shadow_ray(&Bounded_Intersection, Light_Source_Ray, Light_Colour);
  953.  
  954.         if ((fabs(Light_Colour[RED])   < BLACK_LEVEL) &&
  955.             (fabs(Light_Colour[GREEN]) < BLACK_LEVEL) &&
  956.             (fabs(Light_Colour[BLUE])  < BLACK_LEVEL) &&
  957.             (Test_Flag(Bounded_Intersection.Object, OPAQUE_FLAG)))
  958.         {
  959.           Cache_Me = Not_Found_Shadow;
  960.  
  961.           break;
  962.         }
  963.  
  964.         /* Move the ray to the point of intersection, plus some */
  965.  
  966.         *Light_Source_Depth -= Bounded_Intersection.Depth;
  967.  
  968.         Assign_Vector(Light_Source_Ray->Initial, Bounded_Intersection.IPoint);
  969.  
  970.         Not_Found_Shadow = FALSE;
  971.       }
  972.       else
  973.       {
  974.         /* No intersections in the direction of the ray. */
  975.  
  976.         break;
  977.       }
  978.     }
  979.   }
  980.   else
  981.   {
  982.     /* Use bounding slabs to look for shadows. */
  983.  
  984.     while (!Quit_Looking)
  985.     {
  986.       Increase_Counter(stats[Shadow_Ray_Tests]);
  987.  
  988.       Bounded_Intersection.Depth = *Light_Source_Depth;
  989.  
  990.       if (Intersect_BBox_Tree(Root_Object, Light_Source_Ray, &Bounded_Intersection, &Blocking_Object))
  991.       {
  992.         if (Bounded_Intersection.Depth > *Light_Source_Depth)
  993.         {
  994.           /* Intersection was beyond the light. */
  995.  
  996.           break;
  997.         }
  998.  
  999.         if (!Test_Flag(Bounded_Intersection.Object, NO_SHADOW_FLAG))
  1000.         {
  1001.           if (Blocking_Object != Light_Source->Shadow_Cached_Object)
  1002.           {
  1003.             Increase_Counter(stats[Shadow_Rays_Succeeded]);
  1004.  
  1005.             filter_shadow_ray(&Bounded_Intersection, Light_Source_Ray, Light_Colour);
  1006.  
  1007.             if ((fabs(Light_Colour[RED])   < BLACK_LEVEL) &&
  1008.                 (fabs(Light_Colour[GREEN]) < BLACK_LEVEL) &&
  1009.                 (fabs(Light_Colour[BLUE])  < BLACK_LEVEL) &&
  1010.                 (Test_Flag(Blocking_Object, OPAQUE_FLAG)))
  1011.             {
  1012.               Cache_Me = Not_Found_Shadow;
  1013.  
  1014.               break; /* from while */
  1015.             }
  1016.           }
  1017.         }
  1018.  
  1019.         /* Move the ray to the point of intersection, plus some */
  1020.  
  1021.         *Light_Source_Depth -= Bounded_Intersection.Depth;
  1022.  
  1023.         Assign_Vector(Light_Source_Ray->Initial, Bounded_Intersection.IPoint);
  1024.  
  1025.         Not_Found_Shadow = FALSE;
  1026.       }
  1027.       else
  1028.       {
  1029.         /* No intersections in the direction of the ray */
  1030.  
  1031.         break;
  1032.       }
  1033.     }
  1034.   }
  1035.  
  1036.   if (Cache_Me)
  1037.   {
  1038.     Light_Source->Shadow_Cached_Object = Blocking_Object;
  1039.   }
  1040.  
  1041.   close_istack (Local_Stack);
  1042. }
  1043.  
  1044.  
  1045.  
  1046. /*****************************************************************************
  1047. *
  1048. * FUNCTION
  1049. *
  1050. *   block_area_light
  1051. *
  1052. * INPUT
  1053. *
  1054. *   Light_Source       - Light source to test
  1055. *   IPoint             -
  1056. *   u1, v1, u2, v2     -
  1057. *   Level              -
  1058. *
  1059. * OUTPUT
  1060. *
  1061. *   Light_Source_Depth - (Remaining) distance to the light source
  1062. *   Light_Source_Ray   - (Remaining) ray to the light source
  1063. *   Light_Colour       - Color reaching initial point from light source
  1064. *
  1065. * RETURNS
  1066. *
  1067. * AUTHOR
  1068. *
  1069. *   POV-Ray Team
  1070. *
  1071. * DESCRIPTION
  1072. *
  1073. *   Get shadow for given area light source by recursively sampling
  1074. *   on the light source area.
  1075. *
  1076. *   The viewing ray is used to initialize the ray containers of the
  1077. *   light source ray.
  1078. *
  1079. * CHANGES
  1080. *
  1081. *   -
  1082. *
  1083. ******************************************************************************/
  1084.  
  1085. static void block_area_light (Light_Source, Light_Source_Depth,
  1086.   Light_Source_Ray, Eye_Ray, IPoint, Light_Colour, u1, v1, u2, v2, Level)
  1087. LIGHT_SOURCE *Light_Source;
  1088. DBL *Light_Source_Depth;
  1089. RAY *Light_Source_Ray, *Eye_Ray;
  1090. VECTOR IPoint;
  1091. COLOUR Light_Colour;
  1092. int u1, v1, u2, v2, Level;
  1093. {
  1094.   COLOUR Sample_Colour[4], Dummy_Colour;
  1095.   VECTOR Center_Save, NewAxis1, NewAxis2;
  1096.   int i, j, u, v, New_u1, New_v1, New_u2, New_v2;
  1097.  
  1098.   DBL Jitter_u, Jitter_v, ScaleFactor;
  1099.  
  1100.   /* First call, initialize */
  1101.  
  1102.   if ((u1 == 0) && (v1 == 0) && (u2 == 0) && (v2 == 0))
  1103.   {
  1104.     /* Flag uncalculated points with a negative value for Red */
  1105.  
  1106.     for (i = 0; i < Light_Source->Area_Size1; i++)
  1107.     {
  1108.       for (j = 0; j < Light_Source->Area_Size2; j++)
  1109.       {
  1110.         Light_Source->Light_Grid[i][j][RED] = -1.0;
  1111.       }
  1112.     }
  1113.  
  1114.     u1 = 0;
  1115.     v1 = 0;
  1116.     u2 = Light_Source->Area_Size1 - 1;
  1117.     v2 = Light_Source->Area_Size2 - 1;
  1118.   }
  1119.  
  1120.   /* Save the light source center since we'll be fiddling with it */
  1121.  
  1122.   Assign_Vector(Center_Save,Light_Source->Center);
  1123.  
  1124.   /* Sample the four corners of the region */
  1125.  
  1126.   for (i = 0; i < 4; i++)
  1127.   {
  1128.     switch (i)
  1129.     {
  1130.       case 0: u = u1; v = v1; break;
  1131.       case 1: u = u2; v = v1; break;
  1132.       case 2: u = u1; v = v2; break;
  1133.       case 3: u = u2; v = v2; break;
  1134.       default: u = v = 0;  /* Should never happen! */
  1135.     }
  1136.  
  1137.     if (Light_Source->Light_Grid[u][v][RED] >= 0.0)
  1138.     {
  1139.       /* We've already calculated this point, reuse it */
  1140.  
  1141.       Assign_Colour(Sample_Colour[i],Light_Source->Light_Grid[u][v]);
  1142.     }
  1143.     else
  1144.     {
  1145.       Jitter_u = (DBL)u;
  1146.       Jitter_v = (DBL)v;
  1147.  
  1148.       if (Light_Source->Jitter)
  1149.       {
  1150.         Jitter_u += FRAND() - 0.5;
  1151.         Jitter_v += FRAND() - 0.5;
  1152.       }
  1153.  
  1154.       if (Light_Source->Area_Size1 > 1)
  1155.       {
  1156.         ScaleFactor = Jitter_u/(DBL)(Light_Source->Area_Size1 - 1) - 0.5;
  1157.  
  1158.         VScale (NewAxis1, Light_Source->Axis1, ScaleFactor)
  1159.       }
  1160.       else
  1161.       {
  1162.         Make_Vector(NewAxis1, 0.0, 0.0, 0.0);
  1163.       }
  1164.  
  1165.       if (Light_Source->Area_Size2 > 1)
  1166.       {
  1167.         ScaleFactor = Jitter_v/(DBL)(Light_Source->Area_Size2 - 1) - 0.5;
  1168.  
  1169.         VScale (NewAxis2, Light_Source->Axis2, ScaleFactor)
  1170.       }
  1171.       else
  1172.       {
  1173.         Make_Vector(NewAxis2, 0.0, 0.0, 0.0);
  1174.       }
  1175.  
  1176.       Assign_Vector(Light_Source->Center, Center_Save);
  1177.  
  1178.       VAddEq(Light_Source->Center, NewAxis1);
  1179.       VAddEq(Light_Source->Center, NewAxis2);
  1180.  
  1181.       /* Recalculate the light source ray but not the colour */
  1182.  
  1183.       do_light(Light_Source, Light_Source_Depth, Light_Source_Ray, Eye_Ray, IPoint, Dummy_Colour);
  1184.  
  1185.       Assign_Colour(Sample_Colour[i], Light_Colour);
  1186.  
  1187.       block_point_light(Light_Source, Light_Source_Depth, Light_Source_Ray, Sample_Colour[i]);
  1188.  
  1189.       Assign_Colour(Light_Source->Light_Grid[u][v], Sample_Colour[i]);
  1190.     }
  1191.   }
  1192.  
  1193.   Assign_Vector(Light_Source->Center,Center_Save);
  1194.  
  1195.   if ((u2 - u1 > 1) || (v2 - v1 > 1))
  1196.   {
  1197.     if ((Level < Light_Source->Adaptive_Level) ||
  1198.         (Colour_Distance(Sample_Colour[0], Sample_Colour[1]) > 0.1) ||
  1199.         (Colour_Distance(Sample_Colour[1], Sample_Colour[3]) > 0.1) ||
  1200.         (Colour_Distance(Sample_Colour[3], Sample_Colour[2]) > 0.1) ||
  1201.         (Colour_Distance(Sample_Colour[2], Sample_Colour[0]) > 0.1))
  1202.     {
  1203.       for (i = 0; i < 4; i++)
  1204.       {
  1205.         switch (i)
  1206.         {
  1207.           case 0:
  1208.  
  1209.             New_u1 = u1;
  1210.             New_v1 = v1;
  1211.             New_u2 = (int)floor ((u1 + u2)/2.0);
  1212.             New_v2 = (int)floor ((v1 + v2)/2.0);
  1213.  
  1214.             break;
  1215.  
  1216.           case 1:
  1217.  
  1218.             New_u1 = (int)ceil  ((u1 + u2)/2.0);
  1219.             New_v1 = v1;
  1220.             New_u2 = u2;
  1221.             New_v2 = (int)floor ((v1 + v2)/2.0);
  1222.  
  1223.             break;
  1224.  
  1225.           case 2:
  1226.  
  1227.             New_u1 = u1;
  1228.             New_v1 = (int)ceil  ((v1 + v2)/2.0);
  1229.             New_u2 = (int)floor ((u1 + u2)/2.0);
  1230.             New_v2 = v2;
  1231.  
  1232.             break;
  1233.  
  1234.           case 3:
  1235.  
  1236.             New_u1 = (int)ceil ((u1 + u2)/2.0);
  1237.             New_v1 = (int)ceil ((v1 + v2)/2.0);
  1238.             New_u2 = u2;
  1239.             New_v2 = v2;
  1240.  
  1241.             break;
  1242.  
  1243.           default:  /* Should never happen! */
  1244.  
  1245.             New_u1 = New_u2 = New_v1 = New_v2 = 0;
  1246.         }
  1247.  
  1248.         /* Recalculate the light source ray but not the colour */
  1249.  
  1250.         do_light(Light_Source, Light_Source_Depth, Light_Source_Ray, Eye_Ray, IPoint, Dummy_Colour);
  1251.  
  1252.         Assign_Colour(Sample_Colour[i],Light_Colour);
  1253.  
  1254.         block_area_light (Light_Source, Light_Source_Depth, Light_Source_Ray, Eye_Ray,
  1255.           IPoint, Sample_Colour[i], New_u1, New_v1, New_u2, New_v2, Level+1);
  1256.       }
  1257.     }
  1258.   }
  1259.  
  1260.   /* Add up the light contributions */
  1261.  
  1262.   Make_Colour (Light_Colour, 0.0, 0.0, 0.0);
  1263.  
  1264.   for (i = 0; i < 4; i++)
  1265.   {
  1266.     Scale_Colour (Sample_Colour[i], Sample_Colour[i], 0.25);
  1267.  
  1268.     Add_Colour (Light_Colour, Light_Colour, Sample_Colour[i]);
  1269.   }
  1270. }
  1271.  
  1272.  
  1273.  
  1274. /*****************************************************************************
  1275. *
  1276. * FUNCTION
  1277. *
  1278. *   do_light
  1279. *
  1280. * INPUT
  1281. *
  1282. *   Light_Source       - Light source
  1283. *   Light_Source_Depth - Distance from surface to light source
  1284. *   Light_Source_Ray   - Ray from surface to light source
  1285. *   Eye_Ray            - Current viewing ray
  1286. *   IPoint             - Intersection point in surface
  1287. *   Colour             - Light's colour
  1288. *
  1289. * OUTPUT
  1290. *
  1291. *   Light_Source_Depth, Light_Source_Ray, Colour
  1292. *
  1293. * RETURNS
  1294. *
  1295. * AUTHOR
  1296. *
  1297. *   POV-Ray Team
  1298. *
  1299. * DESCRIPTION
  1300. *
  1301. *   The viewing ray is used to initialize the ray containers of the
  1302. *   light source ray.
  1303. *
  1304. * CHANGES
  1305. *
  1306. *   -
  1307. *
  1308. ******************************************************************************/
  1309.  
  1310. static void do_light(Light_Source, Light_Source_Depth, Light_Source_Ray, Eye_Ray, IPoint, Light_Colour)
  1311. LIGHT_SOURCE *Light_Source;
  1312. DBL *Light_Source_Depth;
  1313. RAY *Light_Source_Ray, *Eye_Ray;
  1314. VECTOR IPoint;
  1315. COLOUR Light_Colour;
  1316. {
  1317.   DBL Attenuation;
  1318.  
  1319.   /* Get the light source colour. */
  1320.  
  1321.   Assign_Colour(Light_Colour, Light_Source->Colour);
  1322.  
  1323.   /*
  1324.    * Get the light ray starting at the intersection point and pointing
  1325.    * towards the light source.
  1326.    */
  1327.  
  1328.   Assign_Vector(Light_Source_Ray->Initial, IPoint);
  1329.  
  1330.   VSub(Light_Source_Ray->Direction,Light_Source->Center, IPoint);
  1331.  
  1332.   VLength(*Light_Source_Depth, Light_Source_Ray->Direction);
  1333.  
  1334.   VInverseScaleEq(Light_Source_Ray->Direction, *Light_Source_Depth);
  1335.  
  1336.   /* Attenuate light source color. */
  1337.  
  1338.   Attenuation = Attenuate_Light(Light_Source, Light_Source_Ray, *Light_Source_Depth);
  1339.  
  1340.   /* Now scale the color by the attenuation */
  1341.  
  1342.   VScaleEq(Light_Colour, Attenuation);
  1343.  
  1344.   /* Init ray containers. */
  1345.  
  1346.   Initialize_Ray_Containers(Light_Source_Ray);
  1347.  
  1348.   Copy_Ray_Containers(Light_Source_Ray, Eye_Ray);
  1349. }
  1350.  
  1351.  
  1352.  
  1353. /*****************************************************************************
  1354. *
  1355. * FUNCTION
  1356. *
  1357. *   do_diffuse
  1358. *
  1359. * INPUT
  1360. *
  1361. * OUTPUT
  1362. *
  1363. * RETURNS
  1364. *
  1365. * AUTHOR
  1366. *
  1367. *   POV-Ray Team
  1368. *
  1369. * DESCRIPTION
  1370. *
  1371. *   Calculate the diffuse color component I_d given by:
  1372. *
  1373. *     I_d = a * d * I * C * (N . L) ^ b
  1374. *
  1375. *   where d : surface's diffuse reflection coefficient
  1376. *         b : surface's brilliance
  1377. *         C : surface's color
  1378. *         N : surface's normal vector
  1379. *         L : light vector (pointing at the light)
  1380. *         I : intensity of the incoming light
  1381. *         a : attenuation factor
  1382. *
  1383. * CHANGES
  1384. *
  1385. *   -
  1386. *
  1387. ******************************************************************************/
  1388.  
  1389. static void do_diffuse(Finish, Light_Source_Ray, Layer_Normal, Colour, Light_Colour, Layer_Pigment_Colour, Attenuation)
  1390. FINISH *Finish;
  1391. RAY *Light_Source_Ray;
  1392. VECTOR Layer_Normal;
  1393. COLOUR Colour, Light_Colour, Layer_Pigment_Colour;
  1394. DBL Attenuation;
  1395. {
  1396.   DBL Cos_Angle_Of_Incidence, Intensity;
  1397.  
  1398.   VDot(Cos_Angle_Of_Incidence, Layer_Normal, Light_Source_Ray->Direction);
  1399.  
  1400.   /* Brilliance is likely to be 1.0 (default value) */
  1401.  
  1402.   if (Finish->Brilliance != 1.0)
  1403.   {
  1404.     Intensity = pow(fabs(Cos_Angle_Of_Incidence), Finish->Brilliance);
  1405.   }
  1406.   else
  1407.   {
  1408.     Intensity = fabs(Cos_Angle_Of_Incidence);
  1409.   }
  1410.  
  1411.   Intensity *= Finish->Diffuse * Attenuation;
  1412.  
  1413.   if (Finish->Crand > 0.0)
  1414.   {
  1415.     Intensity -= FRAND() * Finish->Crand;
  1416.   }
  1417.  
  1418.   Colour[RED]   += Intensity * Layer_Pigment_Colour[RED]   * Light_Colour[RED];
  1419.   Colour[GREEN] += Intensity * Layer_Pigment_Colour[GREEN] * Light_Colour[GREEN];
  1420.   Colour[BLUE]  += Intensity * Layer_Pigment_Colour[BLUE]  * Light_Colour[BLUE];
  1421. }
  1422.  
  1423.  
  1424.  
  1425. /*****************************************************************************
  1426. *
  1427. * FUNCTION
  1428. *
  1429. *   do_irid
  1430. *
  1431. * INPUT
  1432. *
  1433. * OUTPUT
  1434. *
  1435. * RETURNS
  1436. *
  1437. * AUTHOR
  1438. *
  1439. *   Dan Farmer
  1440. *
  1441. * DESCRIPTION
  1442. *
  1443. *   IRIDESCENCE:
  1444. *   -----------
  1445. *   Programmed by Dan Farmer.
  1446. *
  1447. *   Based on Chapter 10.2.4 of Three-Dimensional Computer Graphics
  1448. *   by Alan Watt.
  1449. *
  1450. *   Modulates the diffuse coefficients as a function of wavelength, the angle
  1451. *   between the light direction vector, and the surface normal.  It models
  1452. *   thin-film interference, as in a soap bubble or oilslick.
  1453. *
  1454. *   Wavelength at which cancellation offurs is a function of the refractive
  1455. *   index of the film, its thickness, and the angle of incidence of the
  1456. *   incoming light.  In this implementation, IOR is kept constant, while the
  1457. *   thickness of the film is specified, as well as being modulated with a
  1458. *   turbulence function.
  1459. *
  1460. * CHANGES
  1461. *
  1462. *   -
  1463. *
  1464. ******************************************************************************/
  1465.  
  1466. static void do_irid(Finish, Light_Source_Ray, Layer_Normal, IPoint, Colour)
  1467. FINISH *Finish;
  1468. RAY *Light_Source_Ray;
  1469. VECTOR Layer_Normal, IPoint;
  1470. COLOUR Colour;
  1471. {
  1472.   DBL rwl, gwl, bwl;
  1473.   DBL Cos_Angle_Of_Incidence, interference;
  1474.   DBL film_thickness;
  1475.   DBL noise, intensity;
  1476.   TURB Turb;
  1477.  
  1478.   film_thickness = Finish->Irid_Film_Thickness;
  1479.  
  1480.   if (Finish->Irid_Turb != 0)
  1481.   {
  1482.     /* Uses hardcoded octaves, lambda, omega */
  1483.     Turb.Omega=0.5;
  1484.     Turb.Lambda=2.0;
  1485.     Turb.Octaves=5;
  1486.  
  1487.     noise = Turbulence(IPoint, &Turb) * Finish->Irid_Turb;
  1488.  
  1489.     film_thickness *= noise;
  1490.   }
  1491.  
  1492.   /*
  1493.    * Approximate dominant wavelengths of primary hues.
  1494.    * Source: 3D Computer Graphics by John Vince (Addison Wesely)
  1495.    * These are initialized in parse.c (Parse_Frame)
  1496.    * and are user-adjustable with the irid_wavelength keyword.
  1497.    * Red = 700 nm  Grn = 520 nm Blu = 480 nm
  1498.    * Divided by 100 gives: rwl = 0.70;  gwl = 0.52;  bwl = 0.48;
  1499.    *
  1500.    * However... I originally "guessed" at the values and came up with
  1501.    * the following, which I'm using as the defaults, since it seems
  1502.    * to work better:  rwl = 0.25;  gwl = 0.18;  bwl = 0.14;
  1503.    */
  1504.  
  1505.   /* Could avoid these assignments if we want to */
  1506.  
  1507.   rwl = Frame.Irid_Wavelengths[RED];
  1508.   gwl = Frame.Irid_Wavelengths[GREEN];
  1509.   bwl = Frame.Irid_Wavelengths[BLUE];
  1510.  
  1511.   /* NOTE: Shouldn't we compute Cos_Angle_Of_Incidence just once? */
  1512.  
  1513.   VDot(Cos_Angle_Of_Incidence, Layer_Normal, Light_Source_Ray->Direction);
  1514.  
  1515.   /* Calculate phase offset. */
  1516.  
  1517.   interference = 4.0 * M_PI * film_thickness * Cos_Angle_Of_Incidence;
  1518.  
  1519.   intensity = Cos_Angle_Of_Incidence * Finish->Irid;
  1520.  
  1521.   /* Modify color by phase offset for each wavelength. */
  1522.  
  1523.   Colour[RED]  += Finish->Irid * (intensity * (1.0 - 0.5 * cos(interference/rwl)));
  1524.   Colour[GREEN]+= Finish->Irid * (intensity * (1.0 - 0.5 * cos(interference/gwl)));
  1525.   Colour[BLUE] += Finish->Irid * (intensity * (1.0 - 0.5 * cos(interference/bwl)));
  1526. }
  1527.  
  1528.  
  1529.  
  1530. /*****************************************************************************
  1531. *
  1532. * FUNCTION
  1533. *
  1534. *   do_phong
  1535. *
  1536. * INPUT
  1537. *
  1538. * OUTPUT
  1539. *
  1540. * RETURNS
  1541. *
  1542. * AUTHOR
  1543. *
  1544. *   POV-Ray Team
  1545. *
  1546. * DESCRIPTION
  1547. *
  1548. *   Calculate the phong reflected color component I_p given by:
  1549. *
  1550. *     I_p = p * C * (R . L) ^ s
  1551. *
  1552. *   where p : surface's phong reflection coefficient
  1553. *         s : surface's phong size
  1554. *         C : surface's color/light color depending on the metallic flag
  1555. *         R : reflection vector
  1556. *         L : light vector (pointing at the light)
  1557. *
  1558. *   The reflection vector is calculated from the surface normal and
  1559. *   the viewing vector (looking at the surface point):
  1560. *
  1561. *     R = -2 * (V . N) * N + V, with R . R = 1
  1562. *
  1563. * CHANGES
  1564. *
  1565. *   Sep 1994 : Added improved color calculation for metallic surfaces. [DB]
  1566. *
  1567. ******************************************************************************/
  1568.  
  1569. static void do_phong(Finish, Light_Source_Ray, Eye, Layer_Normal, Colour, Light_Colour, Layer_Pigment_Colour)
  1570. FINISH *Finish;
  1571. RAY *Light_Source_Ray;
  1572. VECTOR Layer_Normal, Eye;
  1573. COLOUR Colour, Light_Colour, Layer_Pigment_Colour;
  1574. {
  1575.   DBL Cos_Angle_Of_Incidence, Intensity;
  1576.   VECTOR Reflect_Direction;
  1577.   DBL NdotL, x, F;
  1578.   COLOUR Cs;
  1579.  
  1580.   VDot(Cos_Angle_Of_Incidence, Eye, Layer_Normal);
  1581.  
  1582.   Cos_Angle_Of_Incidence *= -2.0;
  1583.  
  1584.   VLinComb2(Reflect_Direction, 1.0, Eye, Cos_Angle_Of_Incidence, Layer_Normal);
  1585.  
  1586.   VDot(Cos_Angle_Of_Incidence, Reflect_Direction, Light_Source_Ray->Direction);
  1587.  
  1588.   if (Cos_Angle_Of_Incidence > 0.0)
  1589.   {
  1590.     Intensity = Finish->Phong * pow(Cos_Angle_Of_Incidence, Finish->Phong_Size);
  1591.  
  1592.     if (Finish->Metallic > 0.0)
  1593.     {
  1594.       /*
  1595.        * Calculate the reflected color by interpolating between
  1596.        * the light source color and the surface color according
  1597.        * to the (empirical) Fresnel reflectivity function. [DB 9/94]
  1598.        */
  1599.  
  1600.       VDot(NdotL, Layer_Normal, Light_Source_Ray->Direction);
  1601.  
  1602.       x = fabs(acos(NdotL)) / M_PI_2;
  1603.  
  1604.       F = 0.014567225 / Sqr(x - 1.12) - 0.011612903;
  1605.  
  1606.       Cs[RED]   = Light_Colour[RED]   * (1.0 + Finish->Metallic * (1.0 - F) * (Layer_Pigment_Colour[RED]   - 1.0));
  1607.       Cs[GREEN] = Light_Colour[GREEN] * (1.0 + Finish->Metallic * (1.0 - F) * (Layer_Pigment_Colour[GREEN] - 1.0));
  1608.       Cs[BLUE]  = Light_Colour[BLUE]  * (1.0 + Finish->Metallic * (1.0 - F) * (Layer_Pigment_Colour[BLUE]  - 1.0));
  1609.  
  1610.       VAddScaledEq(Colour, Intensity, Cs);
  1611.     }
  1612.     else
  1613.     {
  1614.       Colour[RED]   += Intensity * Light_Colour[RED];
  1615.       Colour[GREEN] += Intensity * Light_Colour[GREEN];
  1616.       Colour[BLUE]  += Intensity * Light_Colour[BLUE];
  1617.     }
  1618.   }
  1619. }
  1620.  
  1621.  
  1622.  
  1623. /*****************************************************************************
  1624. *
  1625. * FUNCTION
  1626. *
  1627. *   do_specular
  1628. *
  1629. * INPUT
  1630. *
  1631. * OUTPUT
  1632. *
  1633. * INPUT
  1634. *
  1635. * OUTPUT
  1636. *
  1637. * RETURNS
  1638. *
  1639. * AUTHOR
  1640. *
  1641. *   POV-Ray Team
  1642. *
  1643. * DESCRIPTION
  1644. *
  1645. *   Calculate the specular reflected color component I_s given by:
  1646. *
  1647. *     I_s = s * C * (H . N) ^ (1 / r)
  1648. *
  1649. *   where s : surface's specular reflection coefficient
  1650. *         r : surface's roughness
  1651. *         C : surface's color/light color depending on the metallic flag
  1652. *         N : surface's normal
  1653. *         H : bisection vector between V and L
  1654. *
  1655. *   The bisecting vector H is calculated by
  1656. *
  1657. *     H = (L - V) / sqrt((L - V).(L - V))
  1658. *
  1659. * CHANGES
  1660. *
  1661. *   Sep 1994 : Added improved color calculation for metallic surfaces. [DB]
  1662. *
  1663. ******************************************************************************/
  1664.  
  1665. static void do_specular(Finish, Light_Source_Ray, REye, Layer_Normal, Colour, Light_Colour, Layer_Pigment_Colour)
  1666. FINISH *Finish;
  1667. RAY *Light_Source_Ray;
  1668. VECTOR Layer_Normal, REye;
  1669. COLOUR Colour, Light_Colour, Layer_Pigment_Colour;
  1670. {
  1671.   DBL Cos_Angle_Of_Incidence, Intensity, Halfway_Length;
  1672.   VECTOR Halfway;
  1673.   DBL NdotL, x, F;
  1674.   COLOUR Cs;
  1675.  
  1676.   VHalf(Halfway, REye, Light_Source_Ray->Direction);
  1677.  
  1678.   VLength(Halfway_Length, Halfway);
  1679.  
  1680.   if (Halfway_Length > 0.0)
  1681.   {
  1682.     VDot(Cos_Angle_Of_Incidence, Halfway, Layer_Normal);
  1683.  
  1684.     Cos_Angle_Of_Incidence /= Halfway_Length;
  1685.  
  1686.     if (Cos_Angle_Of_Incidence > 0.0)
  1687.     {
  1688.       Intensity = Finish->Specular * pow(Cos_Angle_Of_Incidence, Finish->Roughness);
  1689.  
  1690.       if (Finish->Metallic > 0.0)
  1691.       {
  1692.         /*
  1693.          * Calculate the reflected color by interpolating between
  1694.          * the light source color and the surface color according
  1695.          * to the (empirical) Fresnel reflectivity function. [DB 9/94]
  1696.          */
  1697.  
  1698.         VDot(NdotL, Layer_Normal, Light_Source_Ray->Direction);
  1699.  
  1700.         x = fabs(acos(NdotL)) / M_PI_2;
  1701.  
  1702.         F = 0.014567225 / Sqr(x - 1.12) - 0.011612903;
  1703.  
  1704.         Cs[RED]   = Light_Colour[RED]   * (1.0 + Finish->Metallic * (1.0 - F) * (Layer_Pigment_Colour[RED]   - 1.0));
  1705.         Cs[GREEN] = Light_Colour[GREEN] * (1.0 + Finish->Metallic * (1.0 - F) * (Layer_Pigment_Colour[GREEN] - 1.0));
  1706.         Cs[BLUE]  = Light_Colour[BLUE]  * (1.0 + Finish->Metallic * (1.0 - F) * (Layer_Pigment_Colour[BLUE]  - 1.0));
  1707.  
  1708.         VAddScaledEq(Colour, Intensity, Cs);
  1709.       }
  1710.       else
  1711.       {
  1712.         Colour[RED]   += Intensity * Light_Colour[RED];
  1713.         Colour[GREEN] += Intensity * Light_Colour[GREEN];
  1714.         Colour[BLUE]  += Intensity * Light_Colour[BLUE];
  1715.       }
  1716.     }
  1717.   }
  1718. }
  1719.  
  1720.  
  1721.  
  1722. /*****************************************************************************
  1723. *
  1724. * FUNCTION
  1725. *
  1726. *   Diffuse
  1727. *
  1728. * INPUT
  1729. *
  1730. * OUTPUT
  1731. *
  1732. * RETURNS
  1733. *
  1734. * AUTHOR
  1735. *
  1736. *   POV-Ray Team
  1737. *
  1738. * DESCRIPTION
  1739. *
  1740. *   -
  1741. *
  1742. * CHANGES
  1743. *
  1744. *   -
  1745. *
  1746. ******************************************************************************/
  1747.  
  1748. static void Diffuse (Finish, IPoint, Eye, Layer_Normal, Layer_Pigment_Colour, Colour, Attenuation, Object)
  1749. FINISH *Finish;
  1750. VECTOR IPoint, Layer_Normal;
  1751. COLOUR Layer_Pigment_Colour;
  1752. COLOUR Colour;
  1753. RAY    *Eye;
  1754. DBL    Attenuation;
  1755. OBJECT *Object;
  1756. {
  1757.   int i;
  1758.   DBL Light_Source_Depth, Cos_Shadow_Angle;
  1759.   RAY Light_Source_Ray;
  1760.   LIGHT_SOURCE *Light_Source;
  1761.   VECTOR REye;
  1762.   COLOUR Light_Colour;
  1763.  
  1764.   if ((Finish->Diffuse == 0.0) && (Finish->Specular == 0.0) && (Finish->Phong == 0.0))
  1765.   {
  1766.     return;
  1767.   }
  1768.  
  1769.   if (Finish->Specular != 0.0)
  1770.   {
  1771.     REye[X] = -Eye->Direction[X];
  1772.     REye[Y] = -Eye->Direction[Y];
  1773.     REye[Z] = -Eye->Direction[Z];
  1774.   }
  1775.  
  1776.   for (i = 0, Light_Source = Frame.Light_Sources;
  1777.        Light_Source != NULL;
  1778.        Light_Source = Light_Source->Next_Light_Source, i++)
  1779.   {
  1780.     /* Get a colour and a ray. */
  1781.  
  1782.     do_light(Light_Source, &Light_Source_Depth, &Light_Source_Ray, Eye, IPoint, Light_Colour);
  1783.  
  1784.     /* Don't calculate spotlights when outside of the light's cone. */
  1785.  
  1786.     if ((fabs(Light_Colour[RED])   < BLACK_LEVEL) &&
  1787.         (fabs(Light_Colour[GREEN]) < BLACK_LEVEL) &&
  1788.         (fabs(Light_Colour[BLUE])  < BLACK_LEVEL))
  1789.     {
  1790.       continue;
  1791.     }
  1792.  
  1793.     /* See if light on far side of surface from camera. */
  1794.  
  1795.     if (!(Object->Type & DOUBLE_ILLUMINATE))
  1796.     {
  1797.       VDot(Cos_Shadow_Angle, Layer_Normal, Light_Source_Ray.Direction);
  1798.  
  1799.       if (Cos_Shadow_Angle < EPSILON)
  1800.       {
  1801.         continue;
  1802.       }
  1803.     }
  1804.  
  1805.     /*
  1806.      * If light source was not blocked by any intervening object, then
  1807.      * calculate it's contribution to the object's overall illumination.
  1808.      */
  1809.  
  1810.     if ((opts.Quality_Flags & Q_SHADOW) && (Light_Source->Light_Type != FILL_LIGHT_SOURCE))
  1811.     {
  1812.       /* If this surface point has already been tested use previous result. */
  1813.  
  1814.       if (Light_List[i].Tested)
  1815.       {
  1816.         Assign_Colour(Light_Colour, Light_List[i].Colour);
  1817.       }
  1818.       else
  1819.       {
  1820.         block_light_source(Light_Source, Light_Source_Depth, &Light_Source_Ray, Eye, IPoint, Light_Colour);
  1821.  
  1822.         /* Store light colour. */
  1823.  
  1824.         Light_List[i].Tested = TRUE;
  1825.  
  1826.         Assign_Colour(Light_List[i].Colour, Light_Colour);
  1827.       }
  1828.     }
  1829.  
  1830.     if ((fabs(Light_Colour[RED])   > BLACK_LEVEL) ||
  1831.         (fabs(Light_Colour[GREEN]) > BLACK_LEVEL) ||
  1832.         (fabs(Light_Colour[BLUE])  > BLACK_LEVEL))
  1833.     {
  1834.       if (Finish->Diffuse > 0.0)
  1835.       {
  1836.         do_diffuse(Finish,&Light_Source_Ray,Layer_Normal,Colour,Light_Colour,Layer_Pigment_Colour, Attenuation);
  1837.       }
  1838.  
  1839.       if (Light_Source->Light_Type!=FILL_LIGHT_SOURCE)
  1840.       {
  1841.         if (Finish->Phong > 0.0)
  1842.         {
  1843.           do_phong(Finish,&Light_Source_Ray,Eye->Direction,Layer_Normal,Colour,Light_Colour, Layer_Pigment_Colour);
  1844.         }
  1845.  
  1846.         if (Finish->Specular > 0.0)
  1847.         {
  1848.           do_specular(Finish,&Light_Source_Ray,REye,Layer_Normal,Colour,Light_Colour, Layer_Pigment_Colour);
  1849.         }
  1850.       }
  1851.  
  1852.       if (Finish->Irid > 0.0)
  1853.       {
  1854.         do_irid(Finish,&Light_Source_Ray,Layer_Normal,IPoint,Colour);
  1855.       }
  1856.  
  1857.     }
  1858.   }
  1859. }
  1860.  
  1861.  
  1862.  
  1863. /*****************************************************************************
  1864. *
  1865. * FUNCTION
  1866. *
  1867. *   Reflect
  1868. *
  1869. * INPUT
  1870. *   
  1871. * OUTPUT
  1872. *   
  1873. * RETURNS
  1874. *   
  1875. * AUTHOR
  1876. *
  1877. *   POV-Ray Team
  1878. *   
  1879. * DESCRIPTION
  1880. *
  1881. *   -
  1882. *
  1883. * CHANGES
  1884. *
  1885. *   -
  1886. *
  1887. ******************************************************************************/
  1888.  
  1889. static void Reflect (Reflection, IPoint, Ray, Layer_Normal, Colour, Weight)
  1890. RGB Reflection;
  1891. VECTOR IPoint;
  1892. RAY *Ray;
  1893. VECTOR Layer_Normal;
  1894. COLOUR Colour;
  1895. DBL Weight;
  1896. {
  1897.   RAY New_Ray;
  1898.   COLOUR Temp_Colour;
  1899.   register DBL Normal_Component;
  1900.  
  1901.   Increase_Counter(stats[Reflected_Rays_Traced]);
  1902.  
  1903.   VDot(Normal_Component, Ray->Direction, Layer_Normal);
  1904.  
  1905.   Normal_Component *= -2.0;
  1906.  
  1907.   VLinComb2(New_Ray.Direction, Normal_Component, Layer_Normal, 1.0, Ray->Direction);
  1908.  
  1909.   Assign_Vector(New_Ray.Initial, IPoint);
  1910.  
  1911.   Copy_Ray_Containers (&New_Ray, Ray);
  1912.  
  1913.   /* Trace reflected ray. */
  1914.  
  1915.   Trace_Level++;
  1916.  
  1917.   Make_Colour (Temp_Colour, 0.0, 0.0, 0.0);
  1918.  
  1919.   Trace (&New_Ray, Temp_Colour, Weight);
  1920.  
  1921.   Trace_Level--;
  1922.  
  1923.   Colour[RED]   += Reflection[RED]   * Temp_Colour[RED];
  1924.   Colour[GREEN] += Reflection[GREEN] * Temp_Colour[GREEN];
  1925.   Colour[BLUE]  += Reflection[BLUE]  * Temp_Colour[BLUE];
  1926. }
  1927.  
  1928.  
  1929.  
  1930. /*****************************************************************************
  1931. *
  1932. * FUNCTION
  1933. *
  1934. *   Refract
  1935. *
  1936. * INPUT
  1937. *   
  1938. * OUTPUT
  1939. *   
  1940. * RETURNS
  1941. *
  1942. * AUTHOR
  1943. *
  1944. *   POV-Ray Team
  1945. *   
  1946. * DESCRIPTION
  1947. *
  1948. *   -
  1949. *
  1950. * CHANGES
  1951. *
  1952. *   Aug 1995 : Modified to correctly handle the contained texture
  1953. *              list in the transmitonly case. [DB]
  1954. *
  1955. ******************************************************************************/
  1956.  
  1957. static void Refract (Object, Texture, IPoint, Ray, Top_Normal, Colour, Weight)
  1958. OBJECT *Object;
  1959. TEXTURE *Texture;
  1960. VECTOR IPoint;
  1961. RAY *Ray;
  1962. VECTOR Top_Normal;
  1963. COLOUR Colour;
  1964. DBL Weight;
  1965. {
  1966.   int texture_nr;
  1967.   register DBL Normal_Component, Temp_IOR;
  1968.   DBL temp, ior;
  1969.   VECTOR Local_Normal;
  1970.   RGB Reflection;
  1971.   COLOUR Temp_Colour;
  1972.   RAY New_Ray;
  1973.  
  1974.   /* Do we have to bend the ray? */
  1975.  
  1976.   if (Top_Normal == NULL)
  1977.   {
  1978.     /* Only transmit the ray. */
  1979.  
  1980.     Assign_Vector(New_Ray.Initial, IPoint);
  1981.     Assign_Vector(New_Ray.Direction, Ray->Direction);
  1982.  
  1983.     Copy_Ray_Containers (&New_Ray, Ray);
  1984.  
  1985.     /* Handle contained textures. */
  1986.  
  1987.     if (Ray->Containing_Index == -1)
  1988.     {
  1989.       /* The ray is entering from the atmosphere */
  1990.  
  1991.       Ray_Enter (&New_Ray, Texture, Object);
  1992.     }
  1993.     else
  1994.     {
  1995.       /* The ray is currently inside an object */
  1996.  
  1997.       if ((texture_nr = Texture_In_Ray_Container(&New_Ray, Texture)) >= 0)
  1998.       {
  1999.         /* The ray is leaving the current object */
  2000.  
  2001.         Ray_Exit (&New_Ray, texture_nr);
  2002.       }
  2003.       else
  2004.       {
  2005.         /* The ray is entering a new object */
  2006.  
  2007.         Ray_Enter (&New_Ray, Texture, Object);
  2008.       }
  2009.     }
  2010.  
  2011.     /* Trace transmitted ray. */
  2012.  
  2013.     Trace_Level++;
  2014.  
  2015.     Increase_Counter(stats[Transmitted_Rays_Traced]);
  2016.  
  2017.     Make_Colour (Temp_Colour, 0.0, 0.0, 0.0);
  2018.  
  2019.     Trace (&New_Ray, Temp_Colour, Weight);
  2020.  
  2021.     Trace_Level--;
  2022.  
  2023.     VAddEq(Colour, Temp_Colour);
  2024.   }
  2025.   else
  2026.   {
  2027.     /* Refract the ray. */
  2028.  
  2029.     Increase_Counter(stats[Refracted_Rays_Traced]);
  2030.  
  2031.     VDot (Normal_Component, Ray->Direction, Top_Normal);
  2032.  
  2033.     if (Normal_Component <= 0.0)
  2034.     {
  2035.       Assign_Vector(Local_Normal, Top_Normal);
  2036.  
  2037.       Normal_Component *= -1.0;
  2038.     }
  2039.     else
  2040.     {
  2041.       VScale (Local_Normal, Top_Normal, -1.0);
  2042.     }
  2043.  
  2044.     Copy_Ray_Containers (&New_Ray, Ray);
  2045.  
  2046.     /* Handle contained textures. */
  2047.  
  2048.     if (Ray->Containing_Index == -1)
  2049.     {
  2050.       /* The ray is entering from the atmosphere */
  2051.  
  2052.       Ray_Enter (&New_Ray, Texture, Object);
  2053.  
  2054.       ior = Frame.Atmosphere_IOR / Texture->Finish->Index_Of_Refraction;
  2055.     }
  2056.     else
  2057.     {
  2058.       /* The ray is currently inside an object */
  2059.  
  2060.       if ((texture_nr = Texture_In_Ray_Container(&New_Ray, Texture)) >= 0)
  2061.       {
  2062.         /* The ray is leaving the current object */
  2063.  
  2064.         Ray_Exit (&New_Ray, texture_nr);
  2065.  
  2066.         if (New_Ray.Containing_Index == -1)
  2067.         {
  2068.           /* The ray is leaving into the atmosphere */
  2069.  
  2070.           Temp_IOR = Frame.Atmosphere_IOR;
  2071.         }
  2072.         else
  2073.         {
  2074.           /* The ray is leaving into another object */
  2075.  
  2076.           Temp_IOR = New_Ray.Containing_IORs[New_Ray.Containing_Index];
  2077.         }
  2078.  
  2079.         ior = Texture->Finish->Index_Of_Refraction / Temp_IOR;
  2080.       }
  2081.       else
  2082.       {
  2083.         /* The ray is entering a new object */
  2084.  
  2085.         Temp_IOR = New_Ray.Containing_IORs[New_Ray.Containing_Index];
  2086.  
  2087.         Ray_Enter (&New_Ray, Texture, Object);
  2088.  
  2089.         ior = Temp_IOR / Texture->Finish->Index_Of_Refraction;
  2090.       }
  2091.     }
  2092.  
  2093.     /* Compute refrated ray direction using Heckbert's method. */
  2094.  
  2095.     temp = 1.0 + Sqr(ior) * (Sqr(Normal_Component) - 1.0);
  2096.  
  2097.     if (temp < 0.0)
  2098.     {
  2099.       /* Total internal reflection occures. */
  2100.  
  2101.       Reflection[RED]  = 1.0 - Texture->Finish->Reflection[RED];
  2102.       Reflection[GREEN]= 1.0 - Texture->Finish->Reflection[GREEN];
  2103.       Reflection[BLUE] = 1.0 - Texture->Finish->Reflection[BLUE];
  2104.  
  2105.       Reflect (Reflection, IPoint, Ray, Top_Normal, Colour, Weight);
  2106.  
  2107.       return;
  2108.     }
  2109.  
  2110.     temp = ior * Normal_Component - sqrt(temp);
  2111.  
  2112.     VLinComb2(New_Ray.Direction, ior, Ray->Direction, temp, Local_Normal);
  2113.  
  2114.     Assign_Vector(New_Ray.Initial,IPoint);
  2115.  
  2116.     /* Trace refracted ray. */
  2117.  
  2118.     Trace_Level++;
  2119.  
  2120.     Make_Colour (Temp_Colour, 0.0, 0.0, 0.0);
  2121.  
  2122.     Trace (&New_Ray, Temp_Colour, Weight);
  2123.  
  2124.     Trace_Level--;
  2125.  
  2126.     VAddScaledEq(Colour, Texture->Finish->Refraction, Temp_Colour);
  2127.   }
  2128. }
  2129.  
  2130.  
  2131.  
  2132. /*****************************************************************************
  2133. *
  2134. * FUNCTION
  2135. *
  2136. *   create_texture_list
  2137. *
  2138. * INPUT
  2139. *
  2140. * OUTPUT
  2141. *
  2142. * RETURNS
  2143. *
  2144. * AUTHOR
  2145. *
  2146. *   Chris Young based on Dieter Bayer code
  2147. *   
  2148. * DESCRIPTION
  2149. *
  2150. *   Get the list of textures used by current object and the list of
  2151. *   appropriate weights for each texture. Only multi-colored objects
  2152. *   will have more than one texture.
  2153. *
  2154. * CHANGES
  2155. *
  2156. *   Feb 1995 : Added code for triangle mesh texturing. [DB]
  2157. *
  2158. *   Jul 1995 : Modified code to use pre-allocated lists. [DB]
  2159. *
  2160. ******************************************************************************/
  2161.  
  2162. static int create_texture_list(Ray_Intersection)
  2163. INTERSECTION *Ray_Intersection;
  2164. {
  2165.   int Texture_Count;
  2166.   BLOB *Blob;
  2167.   MESH_TRIANGLE *Triangle;
  2168.  
  2169.   /* Test, if object is multi-textured. */
  2170.  
  2171.   if (Test_Flag(Ray_Intersection->Object, MULTITEXTURE_FLAG))
  2172.   {
  2173.     /* Handle blobs. */
  2174.  
  2175.     if (Ray_Intersection->Object->Methods == &Blob_Methods)
  2176.     {
  2177.       Blob = (BLOB *)Ray_Intersection->Object;
  2178.  
  2179.       /* Get list of weighted textures. */
  2180.  
  2181.       Determine_Blob_Textures(Blob, Ray_Intersection->IPoint, &Texture_Count, Texture_List, Weight_List);
  2182.     }
  2183.  
  2184.     /* Handle meshes. */
  2185.  
  2186.     if (Ray_Intersection->Object->Methods == &Mesh_Methods)
  2187.     {
  2188.       /* Set texture to triangle's or object's texture. */
  2189.  
  2190.       Triangle = (MESH_TRIANGLE *)Ray_Intersection->Pointer;
  2191.  
  2192.       if (Triangle->Texture >= 0)
  2193.       {
  2194.         Texture_List[0] = ((MESH *)Ray_Intersection->Object)->Data->Textures[Triangle->Texture];
  2195.       }
  2196.       else
  2197.       {
  2198.         Texture_List[0] = Ray_Intersection->Object->Texture;
  2199.       }
  2200.  
  2201.       Weight_List[0] = 1.0;
  2202.  
  2203.       Texture_Count = 1;
  2204.     }
  2205.   }
  2206.   else
  2207.   {
  2208.     /* Set texture to object's texture. */
  2209.  
  2210.     Texture_List[0] = Ray_Intersection->Object->Texture;
  2211.     Weight_List[0]  = 1.0;
  2212.  
  2213.     Texture_Count = 1;
  2214.   }
  2215.  
  2216.   return(Texture_Count);
  2217. }
  2218.  
  2219.  
  2220.  
  2221. /*****************************************************************************
  2222. *
  2223. * FUNCTION
  2224. *
  2225. *   do_texture_map
  2226. *
  2227. * INPUT
  2228. *
  2229. *   Texture          - possibly texture_mapped texture to be evaluated
  2230. *   IPoint           - point to be evaluated
  2231. *   Raw_Normal       - non-purturbed surface normal
  2232. *   Ray              - view ray needed for reflection and highlighs
  2233. *                      light source ray needed for caustics
  2234. *   Weight           - ADC control value
  2235. *   Ray_Intersection - only Ray_Int..->Object->Type actually
  2236. *                      needed.  Will clean-up later.
  2237. *   Shadow_Flag      - tells if computation should use
  2238. *                      compute_lighted_texture or compute_shadow_texture
  2239. *
  2240. * OUTPUT
  2241. *
  2242. *   Result_Colour    - If Shadow_Flag true then the illuminated
  2243. *                      color (RGB only) of IPoint is returned.
  2244. *                      If false, the amount by which a shadow ray is
  2245. *                      filtered and attenuated is returned.
  2246. *                      Includes RGB and T.
  2247. *
  2248. * RETURNS
  2249. *
  2250. * AUTHOR
  2251. *
  2252. *   POV-Ray Team
  2253. *
  2254. * DESCRIPTION
  2255. *
  2256. *   This routine recursively calls itself until it gets a
  2257. *   non-texture_mapped texture that is potentially layered.
  2258. *   It then calls compute_lighted_texture or compute_shadow_texture
  2259. *   to compute the color which is returned in the argument Result_Colour.
  2260. *
  2261. * CHANGES
  2262. *
  2263. ******************************************************************************/
  2264.  
  2265. static void do_texture_map(Result_Colour, Texture, IPoint, Raw_Normal,
  2266.   Ray, Weight, Ray_Intersection, Shadow_Flag)
  2267. COLOUR Result_Colour;
  2268. TEXTURE *Texture;
  2269. VECTOR IPoint, Raw_Normal;
  2270. RAY *Ray;
  2271. DBL Weight;
  2272. INTERSECTION *Ray_Intersection;
  2273. int Shadow_Flag;
  2274. {
  2275.   BLEND_MAP *Blend_Map = Texture->Blend_Map;
  2276.   BLEND_MAP_ENTRY *Prev, *Cur;
  2277.   DBL value1, value2;
  2278.   COLOUR C2;
  2279.   VECTOR TPoint;
  2280.  
  2281.   if (Texture->Type <= LAST_SPECIAL_PATTERN)
  2282.   {
  2283.     switch (Texture->Type)
  2284.     {
  2285.       case NO_PATTERN:
  2286.  
  2287.         Make_ColourA(Result_Colour, 1.0, 1.0, 1.0, 1.0, 1.0);
  2288.  
  2289.         break;
  2290.  
  2291.       case AVERAGE_PATTERN:
  2292.  
  2293.         Warp_EPoint(TPoint, IPoint, (TPATTERN *)Texture);
  2294.  
  2295.         average_textures(Result_Colour, Texture, TPoint, Raw_Normal, Ray, Weight, Ray_Intersection, Shadow_Flag);
  2296.  
  2297.         break;
  2298.  
  2299.       case BITMAP_PATTERN:
  2300.  
  2301.         Warp_EPoint (TPoint, IPoint, (TPATTERN *)Texture);
  2302.  
  2303.         Texture = material_map(TPoint, Texture);
  2304.  
  2305.         do_texture_map(Result_Colour, Texture, TPoint, Raw_Normal, Ray, Weight, Ray_Intersection, Shadow_Flag);
  2306.  
  2307.         break;
  2308.  
  2309.       case PLAIN_PATTERN:
  2310.  
  2311.         if (Shadow_Flag)
  2312.         {
  2313.           compute_shadow_texture(Result_Colour, Texture, IPoint, Raw_Normal, Ray, Ray_Intersection);
  2314.         }
  2315.         else
  2316.         {
  2317.           compute_lighted_texture(Result_Colour, Texture, IPoint, Raw_Normal, Ray, Weight, Ray_Intersection);
  2318.         }
  2319.  
  2320.         break;
  2321.  
  2322.       default:
  2323.  
  2324.         Error("Bad texture type in do_texture_map()\n");
  2325.     }
  2326.   }
  2327.   else
  2328.   {
  2329.     value1 = Evaluate_TPat ((TPATTERN *)Texture,IPoint);
  2330.  
  2331.     Search_Blend_Map (value1, Blend_Map, &Prev, &Cur);
  2332.  
  2333.     Warp_EPoint (TPoint, IPoint, (TPATTERN *)Texture);
  2334.  
  2335.     do_texture_map(Result_Colour, Cur->Vals.Texture, TPoint, Raw_Normal, Ray, Weight, Ray_Intersection, Shadow_Flag);
  2336.  
  2337.     if (Prev != Cur)
  2338.     {
  2339.       do_texture_map(C2, Prev->Vals.Texture, TPoint, Raw_Normal, Ray, Weight, Ray_Intersection, Shadow_Flag);
  2340.  
  2341.       value1 = (value1 - Prev->value) / (Cur->value - Prev->value);
  2342.       value2 = 1.0 - value1;
  2343.  
  2344.       CLinComb2(Result_Colour,value1,Result_Colour,value2,C2);
  2345.     }
  2346.   }
  2347. }
  2348.  
  2349.  
  2350.  
  2351.  
  2352. /*****************************************************************************
  2353. *
  2354. * FUNCTION
  2355. *
  2356. *   compute_lighted_texture
  2357. *
  2358. * INPUT
  2359. *
  2360. *   Texture          - a linked list of texture layers
  2361. *   IPoint           - point to be evaluated
  2362. *   Raw_Normal       - non-purturbed surface normal
  2363. *   Ray              - needed for reflection and highlighs
  2364. *   Weight           - ADC control value
  2365. *   Ray_Intersection - current intersection (need object type and depth)
  2366. *
  2367. * OUTPUT
  2368. *
  2369. *   Result_Colour    - illuminated color of IPoint
  2370. *
  2371. * RETURNS
  2372. *
  2373. * AUTHOR
  2374. *
  2375. *   POV-Ray Team
  2376. *
  2377. * DESCRIPTION
  2378. *
  2379. *   This routine loops through all layers of a texture and computes
  2380. *   the appearent color of the point with illumination, shadows,
  2381. *   reflection, refraction... everything.  This piece of code was broken out
  2382. *   of Determine_Appearent_Colour because texture_map needs to call it twice.
  2383. *
  2384. * CHANGES
  2385. *
  2386. *   Jul 1995 : Added code to support alpha channel. [DB]
  2387. *
  2388. *   Jul 1995 : Moved code for save list allocation. [DB]
  2389. *
  2390. *   Aug 1995 : Added code for distance based attenuation in translucent
  2391. *              objects and halos. [DB]
  2392. *
  2393. ******************************************************************************/
  2394.  
  2395. static void compute_lighted_texture(Result_Colour, Texture, IPoint, Raw_Normal, Ray, Weight, Ray_Intersection)
  2396. COLOUR Result_Colour;
  2397. TEXTURE *Texture;
  2398. VECTOR IPoint, Raw_Normal;
  2399. RAY *Ray;
  2400. DBL Weight;
  2401. INTERSECTION *Ray_Intersection;
  2402. {
  2403.   int i, radiosity_done, radiosity_needed;
  2404.   int layer_number;
  2405.   int calc_halo;
  2406.   int one_colour_found, colour_found;
  2407.   DBL w1, w2;
  2408.   DBL Normal_Direction, New_Weight, Temp_Weight;
  2409.   DBL Attenuation, Transparency, Max_Radiosity_Contribution;
  2410.   VECTOR Layer_Normal, Top_Normal;
  2411.   COLOUR Layer_Pigment_Colour, Refracted_Colour, Filter_Colour;
  2412.   COLOUR Temp_Colour, Gathered_Ambient_Colour, Temp;
  2413.   FINISH *Finish;
  2414.   HALO *Halo;
  2415.   TEXTURE *Layer;
  2416.  
  2417.   /*
  2418.    * Result_Colour builds up the apparent visible color of the point.
  2419.    * Only RGB components are significant.  You can't "see" transparency --
  2420.    * you see the color of whatever is behind the transparent surface.
  2421.    * This color includes the visible appearence of what is behind the
  2422.    * transparency so only RGB is needed.
  2423.    */
  2424.  
  2425.   Make_ColourA(Result_Colour, 0.0, 0.0, 0.0, 0.0, 0.0);
  2426.  
  2427.   /*
  2428.    * Filter_Colour serves two purposes.  It accumulates the filter properties
  2429.    * of a multi-layer texture so that if a ray makes it all the way through
  2430.    * all layers, the color of object behind is filtered by this object.
  2431.    * It also is used to attenuate how much of an underlayer you
  2432.    * can see in a layered texture.  Note that when computing the reflective
  2433.    * properties of a layered texture, the upper layers don't filter the
  2434.    * light from the lower layers -- the layer colors add together (even
  2435.    * before we added additive transparency via the "transmit" 5th
  2436.    * color channel).  However when computing the transmitted rays, all layers
  2437.    * filter the light from any objects behind this object. [CY 1/95]
  2438.    */
  2439.  
  2440.   Make_ColourA(Filter_Colour, 1.0, 1.0, 1.0, 1.0, 1.0);
  2441.  
  2442.   Transparency = 1.0;
  2443.  
  2444.   /* add in radiosity (stochastic interreflection-based ambient light) if desired */
  2445.  
  2446.   radiosity_done = FALSE;
  2447.  
  2448.   /* Note that there is no gathering of filter or transparency */
  2449.  
  2450.   Make_ColourA(Gathered_Ambient_Colour, 1., 1., 1., 0., 0.);
  2451.  
  2452.   if ((opts.Options & RADIOSITY) &&
  2453.       (Trace_Level == Radiosity_Trace_Level) &&
  2454.       (Radiosity_Trace_Level <= opts.Radiosity_Recursion_Limit))
  2455.   {
  2456.     /*
  2457.      * For "real" (physically-based) diffuse interreflections, the
  2458.      * ambient light level is independent of any surface properties, so
  2459.      * the light gathering is done only once.  This block just sets up
  2460.      * for the code inside the loop, which is first-time-through.
  2461.      */
  2462.  
  2463.     /* If the surface normal points away, flip its direction. */
  2464.  
  2465.     VDot(Normal_Direction, Raw_Normal, Ray->Direction);
  2466.  
  2467.     if (Normal_Direction > 0.0)
  2468.     {
  2469.       VScaleEq(Raw_Normal, -1.0);
  2470.     }
  2471.  
  2472.     radiosity_needed = 1;
  2473.   }
  2474.   else
  2475.   {
  2476.     radiosity_needed = 0;
  2477.   }
  2478.  
  2479.   /*
  2480.    * Loop through the layers and compute the ambient, diffuse, reflection
  2481.    * and highlights from these textures.
  2482.    */
  2483.  
  2484.   one_colour_found = FALSE;
  2485.  
  2486.   for (layer_number = 1, Layer = Texture;
  2487.       (Layer != NULL) && (Transparency > BLACK_LEVEL);
  2488.       layer_number++, Layer = (TEXTURE *)Layer->Next)
  2489.   {
  2490.     Assign_Vector(Layer_Normal, Raw_Normal);
  2491.  
  2492.     if ((opts.Quality_Flags & Q_NORMAL) && (Layer->Tnormal != NULL))
  2493.     {
  2494.       Perturb_Normal(Layer_Normal, Layer->Tnormal, IPoint);
  2495.     }
  2496.  
  2497.     /* If the surface normal points away, flip its direction. */
  2498.  
  2499.     VDot(Normal_Direction, Layer_Normal, Ray->Direction);
  2500.  
  2501.     if (Normal_Direction > 0.0)
  2502.     {
  2503.       VScaleEq(Layer_Normal, -1.0);
  2504.     }
  2505.  
  2506.     /* Store top layer normal.*/
  2507.  
  2508.     if (layer_number == 1)
  2509.     {
  2510.       Assign_Vector(Top_Normal,Layer_Normal);
  2511.     }
  2512.  
  2513.     /* Get surface colour. */
  2514.  
  2515.     New_Weight = Weight * Transparency;
  2516.  
  2517.     colour_found = Compute_Pigment (Layer_Pigment_Colour, Layer->Pigment, IPoint);
  2518.  
  2519.     /*
  2520.      * If a valid color was returned set one_colour_found to TRUE.
  2521.      * An invalid color is returned if a surface point is outside
  2522.      * an image map used just once.
  2523.      */
  2524.  
  2525.     if (colour_found)
  2526.     {
  2527.       one_colour_found = TRUE;
  2528.     }
  2529.  
  2530.     /*
  2531.      * This section of code used to be the routine Compute_Reflected_Colour.
  2532.      * I copied it in here to rearrange some of it more easily and to
  2533.      * see if we could eliminate passing a zillion parameters for no
  2534.      * good reason. [CY 1/95]
  2535.      */
  2536.  
  2537.     if (opts.Quality_Flags & Q_FULL_AMBIENT)
  2538.     {
  2539.       /* Only use top layer and kill transparency if low quality */
  2540.  
  2541.       Assign_Colour(Result_Colour, Layer_Pigment_Colour);
  2542.  
  2543.       Result_Colour[FILTER] =
  2544.       Result_Colour[TRANSM] = 0.0;
  2545.     }
  2546.     else
  2547.     {
  2548.       Make_Colour (Temp_Colour, 0.0, 0.0, 0.0);
  2549.  
  2550.       Attenuation = Transparency * (1.0 - min(1.0, Layer_Pigment_Colour[FILTER] + Layer_Pigment_Colour[TRANSM]));
  2551.  
  2552.       /* if radiosity calculation needed, but not yet done, do it now */
  2553.  
  2554.       if (radiosity_needed && !radiosity_done)
  2555.       {
  2556.         /* This check eliminates radiosity calculations on "luminous" objects with ambient=1 */
  2557.  
  2558.         if ((Layer->Finish->Ambient[RED]   != 1.0) ||
  2559.             (Layer->Finish->Ambient[GREEN] != 1.0) ||
  2560.             (Layer->Finish->Ambient[BLUE]  != 1.0))
  2561.         {
  2562.           /* calculate max possible contribution of radiosity, to see if calculating it is worthwhile */
  2563.  
  2564.           Temp[RED]   = Attenuation * Layer_Pigment_Colour[RED] *
  2565.                         Layer->Finish->Ambient[RED] *
  2566.                         Frame.Ambient_Light[RED];
  2567.  
  2568.           Temp[GREEN] = Attenuation * Layer_Pigment_Colour[GREEN] *
  2569.                         Layer->Finish->Ambient[GREEN] *
  2570.                         Frame.Ambient_Light[GREEN];
  2571.  
  2572.           Temp[BLUE]  = Attenuation * Layer_Pigment_Colour[BLUE] *
  2573.                         Layer->Finish->Ambient[BLUE] *
  2574.                         Frame.Ambient_Light[BLUE];
  2575.  
  2576.           Max_Radiosity_Contribution = Temp[RED] *.287 + Temp[GREEN] *.589 + Temp[BLUE] * .114;
  2577.  
  2578.           if (Max_Radiosity_Contribution > BLACK_LEVEL * 3.0)
  2579.           {
  2580.             (void)Compute_Ambient(Ray_Intersection->IPoint, Raw_Normal,
  2581.               Gathered_Ambient_Colour, Weight * Max_Radiosity_Contribution);
  2582.  
  2583.             radiosity_done = TRUE;
  2584.           }
  2585.         }
  2586.       }
  2587.  
  2588.       /* Add ambient contribution. */
  2589.  
  2590.       Temp_Colour[RED]   += Attenuation *
  2591.                             Layer_Pigment_Colour[RED] *
  2592.                             Layer->Finish->Ambient[RED] *
  2593.                             Frame.Ambient_Light[RED] *
  2594.                             Gathered_Ambient_Colour[RED];
  2595.  
  2596.       Temp_Colour[GREEN] += Attenuation *
  2597.                             Layer_Pigment_Colour[GREEN] *
  2598.                             Layer->Finish->Ambient[GREEN] *
  2599.                             Frame.Ambient_Light[GREEN] *
  2600.                             Gathered_Ambient_Colour[GREEN];
  2601.  
  2602.       Temp_Colour[BLUE]  += Attenuation *
  2603.                             Layer_Pigment_Colour[BLUE] *
  2604.                             Layer->Finish->Ambient[BLUE] *
  2605.                             Frame.Ambient_Light[BLUE] *
  2606.                             Gathered_Ambient_Colour[BLUE];
  2607.  
  2608.  
  2609.       /* Add diffuse, phong, specular, and iridescence contribution. */
  2610.  
  2611.       Diffuse (Layer->Finish, Ray_Intersection->IPoint, Ray,
  2612.         Layer_Normal, Layer_Pigment_Colour, Temp_Colour, Attenuation,
  2613.         Ray_Intersection->Object);
  2614.  
  2615.       VAddEq(Result_Colour, Temp_Colour);
  2616.  
  2617.       /* Do reflection. */
  2618.  
  2619.       if (opts.Quality_Flags & Q_REFLECT)
  2620.       {
  2621.         if ((Layer->Finish->Reflection[RED]   != 0.0) ||
  2622.             (Layer->Finish->Reflection[GREEN] != 0.0) ||
  2623.             (Layer->Finish->Reflection[BLUE]  != 0.0))
  2624.         {
  2625.           Temp_Weight = New_Weight * max3(Layer->Finish->Reflection[RED], Layer->Finish->Reflection[GREEN], Layer->Finish->Reflection[BLUE]);
  2626.  
  2627.           Reflect(Layer->Finish->Reflection, Ray_Intersection->IPoint, Ray,
  2628.             Layer_Normal, Result_Colour, Temp_Weight);
  2629.         }
  2630.       }
  2631.     }
  2632.  
  2633.     /*
  2634.      * End of former Compute_Reflected_Colour code.
  2635.      */
  2636.  
  2637.     if (colour_found)
  2638.     {
  2639.       Filter_Colour[RED]    *= Layer_Pigment_Colour[RED];
  2640.       Filter_Colour[GREEN]  *= Layer_Pigment_Colour[GREEN];
  2641.       Filter_Colour[BLUE]   *= Layer_Pigment_Colour[BLUE];
  2642.       Filter_Colour[FILTER] *= Layer_Pigment_Colour[FILTER];
  2643.       Filter_Colour[TRANSM] *= Layer_Pigment_Colour[TRANSM];
  2644.     }
  2645.  
  2646.     Transparency = min(1.0, fabs(Filter_Colour[FILTER]) + fabs(Filter_Colour[TRANSM]));
  2647.   }
  2648.  
  2649.   /*
  2650.    * Now see if any transparency remains.  If it does, then fire a transmitted
  2651.    * ray and add it's contribution to the total Result_Colour after
  2652.    * filtering it by Filter_Colour.
  2653.    */
  2654.  
  2655.   Finish = Texture->Finish;
  2656.  
  2657.   if ((Transparency > BLACK_LEVEL) && (opts.Quality_Flags & Q_REFRACT))
  2658.   {
  2659.     Make_Colour(Refracted_Colour, 0.0, 0.0, 0.0);
  2660.  
  2661.     w1 = fabs(Filter_Colour[FILTER]) * max3(Filter_Colour[RED], Filter_Colour[GREEN], Filter_Colour[BLUE]);
  2662.     w2 = fabs(Filter_Colour[TRANSM]);
  2663.  
  2664.     New_Weight = Weight * max(w1, w2);
  2665.  
  2666.     /*
  2667.      * WARNING: The Refract() routine must be passed the un-transformed
  2668.      * IPoint from Ray_Intersection->IPoint so that the Ray->Initial for
  2669.      * transmitted rays is properly set.  It should not be a TPoint from
  2670.      * some transformed or turbulated texture_map pattern.
  2671.      */
  2672.  
  2673.     if (Finish->Refraction > 0.0)
  2674.     {
  2675.       Refract (Ray_Intersection->Object, Texture, Ray_Intersection->IPoint, Ray, Top_Normal, Refracted_Colour, New_Weight);
  2676.     }
  2677.     else
  2678.     {
  2679.       Refract (Ray_Intersection->Object, Texture, Ray_Intersection->IPoint, Ray, NULL, Refracted_Colour, New_Weight);
  2680.     }
  2681.  
  2682.     /* Get distance based attenuation. */
  2683.  
  2684.     Attenuation = 1.0;
  2685.  
  2686.     if (Ray->Containing_Index > -1)
  2687.     {
  2688.       /* Attenuate light due to light source distance. */
  2689.  
  2690.       if (Texture_In_Ray_Container(Ray, Texture) >= 0)
  2691.       {
  2692.         if ((Finish->Fade_Power > 0.0) && (fabs(Finish->Fade_Distance) > EPSILON))
  2693.         {
  2694.           Attenuation = 1.0 / (1.0 + pow(Ray_Intersection->Depth / Finish->Fade_Distance, Finish->Fade_Power));
  2695.         }
  2696.       }
  2697.     }
  2698.  
  2699.     if (one_colour_found)
  2700.     {
  2701.       Result_Colour[RED]  += Attenuation * Refracted_Colour[RED]   *
  2702.         (Filter_Colour[RED]   * Filter_Colour[FILTER] + Filter_Colour[TRANSM]);
  2703.  
  2704.       Result_Colour[GREEN]+= Attenuation * Refracted_Colour[GREEN] *
  2705.         (Filter_Colour[GREEN] * Filter_Colour[FILTER] + Filter_Colour[TRANSM]);
  2706.  
  2707.       Result_Colour[BLUE] += Attenuation * Refracted_Colour[BLUE]  *
  2708.         (Filter_Colour[BLUE]  * Filter_Colour[FILTER] + Filter_Colour[TRANSM]);
  2709.     }
  2710.     else
  2711.     {
  2712.       Result_Colour[RED]  += Attenuation * Refracted_Colour[RED];
  2713.       Result_Colour[GREEN]+= Attenuation * Refracted_Colour[GREEN];
  2714.       Result_Colour[BLUE] += Attenuation * Refracted_Colour[BLUE];
  2715.     }
  2716.  
  2717.     /* We need to know the transmittance value for the alpha channel. [DB] */
  2718.  
  2719.     Result_Colour[TRANSM] = Attenuation * Filter_Colour[TRANSM];
  2720.   }
  2721.  
  2722.   /* Calculate halo effects. */
  2723.  
  2724.   if ((opts.Quality_Flags & Q_VOLUME) && (Ray->Containing_Index > -1))
  2725.   {
  2726.     calc_halo = TRUE;
  2727.  
  2728.     /* Test for any solid object. */
  2729.  
  2730.     for (i = 0; i <= Ray->Containing_Index; i++)
  2731.     {
  2732.       if (!Test_Flag(Ray->Containing_Objects[i], HOLLOW_FLAG))
  2733.       {
  2734.         calc_halo = FALSE;
  2735.  
  2736.         break;
  2737.       }
  2738.     }
  2739.  
  2740.     /* Calculate effects of all halos we're currently in. */
  2741.  
  2742.     if (calc_halo)
  2743.     {
  2744.       for (i = 0; i <= Ray->Containing_Index; i++)
  2745.       {
  2746.         if ((Halo = Ray->Containing_Textures[i]->Halo) != NULL)
  2747.         {
  2748.           if (Halo->Type != HALO_NO_HALO)
  2749.           {
  2750.             Do_Halo(Halo, Ray, Ray_Intersection, Result_Colour, FALSE);
  2751.           }
  2752.         }
  2753.       }
  2754.     }
  2755.   }
  2756. }
  2757.  
  2758.  
  2759.  
  2760. /*****************************************************************************
  2761. *
  2762. * FUNCTION
  2763. *
  2764. *   compute_shadow_texture
  2765. *
  2766. * INPUT
  2767. *
  2768. *   Texture          - layered texture through which shadow ray passes
  2769. *   IPoint           - point through which shadow ray passes
  2770. *   Raw_Normal       - non-purturbed surface normal
  2771. *   Ray              - light source ray
  2772. *   Ray_Intersection - current intersection (need intersection depth)
  2773. *
  2774. * OUTPUT
  2775. *
  2776. *   Filter_Colour - returned filter for shadow ray
  2777. *
  2778. * RETURNS
  2779. *
  2780. * AUTHOR
  2781. *
  2782. *   POV-Ray Team
  2783. *
  2784. * DESCRIPTION
  2785. *
  2786. * CHANGES
  2787. *
  2788. *   Dec 1994 : Separated from filter_shadow_ray to do texture_map [CEY]
  2789. *
  2790. *   May 1995 : Added caustic code by Steve Anger. [DB]
  2791. *
  2792. *   Aug 1995 : Caustic code moved here from filter_shadow_ray. [CEY]
  2793. *
  2794. ******************************************************************************/
  2795.  
  2796. static void compute_shadow_texture (Filter_Colour, Texture, IPoint, Raw_Normal, Ray, Ray_Intersection)
  2797. COLOUR Filter_Colour;
  2798. TEXTURE *Texture;
  2799. VECTOR IPoint;
  2800. VECTOR Raw_Normal;
  2801. RAY *Ray;
  2802. INTERSECTION *Ray_Intersection;
  2803. {
  2804.   int i, calc_halo, colour_found, one_colour_found;
  2805.   DBL Caustics, dot, k, Refraction;
  2806.   VECTOR Layer_Normal;
  2807.   COLOUR Layer_Pigment_Colour;
  2808.   COLOUR Halo_Colour;
  2809.   FINISH *Finish;
  2810.   HALO *Halo;
  2811.   TEXTURE *Layer;
  2812.  
  2813.   Make_ColourA(Filter_Colour, 1.0, 1.0, 1.0, 1.0, 1.0);
  2814.  
  2815.   one_colour_found = FALSE;
  2816.  
  2817.   for (Layer = Texture; (Layer != NULL) &&
  2818.        (fabs(Filter_Colour[FILTER]) + fabs(Filter_Colour[TRANSM]) > BLACK_LEVEL);
  2819.        Layer = (TEXTURE *)Layer->Next)
  2820.   {
  2821.     colour_found = Compute_Pigment (Layer_Pigment_Colour, Layer->Pigment, IPoint);
  2822.  
  2823.     if (colour_found)
  2824.     {
  2825.       one_colour_found = TRUE;
  2826.     }
  2827.  
  2828.     Refraction = (DBL)((Layer->Finish->Refraction > 0.0) ? Layer->Finish->Refraction : 1.0);
  2829.  
  2830.     /* Get distance based attenuation. */
  2831.  
  2832.     if (Ray->Containing_Index > -1)
  2833.     {
  2834.       /* Get finish of texture we're currently in. */
  2835.  
  2836.       if ((Finish = Ray->Containing_Textures[Ray->Containing_Index]->Finish)!=NULL)
  2837.       {
  2838.          /* Attenuate light due to light source distance. */
  2839.  
  2840.          if (Texture_In_Ray_Container(Ray, Texture) >= 0)
  2841.          {
  2842.            if ((Finish->Fade_Power > 0.0) && (fabs(Finish->Fade_Distance) > EPSILON))
  2843.            {
  2844.              Refraction *= 1.0 / (1.0 + pow(Ray_Intersection->Depth / Finish->Fade_Distance, Finish->Fade_Power));
  2845.            }
  2846.          }
  2847.       }
  2848.     }
  2849.  
  2850.     if (colour_found)
  2851.     {
  2852.       Filter_Colour[RED]    *= Refraction * Layer_Pigment_Colour[RED];
  2853.       Filter_Colour[GREEN]  *= Refraction * Layer_Pigment_Colour[GREEN];
  2854.       Filter_Colour[BLUE]   *= Refraction * Layer_Pigment_Colour[BLUE];
  2855.       Filter_Colour[FILTER] *= Refraction * Layer_Pigment_Colour[FILTER];
  2856.       Filter_Colour[TRANSM] *= Refraction * Layer_Pigment_Colour[TRANSM];
  2857.     }
  2858.     else
  2859.     {
  2860.       Filter_Colour[RED]    *= Refraction;
  2861.       Filter_Colour[GREEN]  *= Refraction;
  2862.       Filter_Colour[BLUE]   *= Refraction;
  2863.       Filter_Colour[FILTER] *= Refraction;
  2864.       Filter_Colour[TRANSM] *= Refraction;
  2865.     }
  2866.  
  2867.     /* Get normal for faked caustics. (Will rewrite later to cache) */
  2868.  
  2869.     if ((Caustics = Layer->Finish->Caustics) != 0.0)
  2870.     {
  2871.       Assign_Vector(Layer_Normal, Raw_Normal);
  2872.  
  2873.       if ((opts.Quality_Flags & Q_NORMAL) && (Layer->Tnormal != NULL))
  2874.       {
  2875.         Perturb_Normal(Layer_Normal, Layer->Tnormal, IPoint);
  2876.       }
  2877.  
  2878.       /* Get new filter/transmit values. */
  2879.  
  2880.       VDot (dot, Layer_Normal, Ray->Direction);
  2881.  
  2882.       k = (1.0 + pow(fabs(dot), Caustics));
  2883.  
  2884.       Filter_Colour[FILTER] *= k;
  2885.       Filter_Colour[TRANSM] *= k;
  2886.     }
  2887.   }
  2888.  
  2889.   /*
  2890.    * If no valid color was found we set the filtering channel
  2891.    * to zero to make sure that no light amplification occures.
  2892.    * That would happen if both the filter and transmit channel
  2893.    * were used.
  2894.    */
  2895.  
  2896.   if (!one_colour_found)
  2897.   {
  2898.     Filter_Colour[FILTER] = 0.0;
  2899.   }
  2900.  
  2901.   /* Calculate halo. */
  2902.  
  2903.   if ((opts.Quality_Flags & Q_VOLUME) && (Ray->Containing_Index > -1))
  2904.   {
  2905.     calc_halo = TRUE;
  2906.  
  2907.     /* Test for any solid object. */
  2908.  
  2909.     for (i = 0; i <= Ray->Containing_Index; i++)
  2910.     {
  2911.       if (!Test_Flag(Ray->Containing_Objects[i], HOLLOW_FLAG))
  2912.       {
  2913.         calc_halo = FALSE;
  2914.  
  2915.         break;
  2916.       }
  2917.     }
  2918.  
  2919.     /* Calculate effects of all halos we're currently in. */
  2920.  
  2921.     if (calc_halo)
  2922.     {
  2923.       for (i = 0; i <= Ray->Containing_Index; i++)
  2924.       {
  2925.         if ((Halo = Ray->Containing_Textures[i]->Halo) != NULL)
  2926.         {
  2927.           if (Halo->Type != HALO_NO_HALO)
  2928.           {
  2929.             Do_Halo(Halo, Ray, Ray_Intersection, Halo_Colour, TRUE);
  2930.           }
  2931.         }
  2932.       }
  2933.     }
  2934.   }
  2935. }
  2936.  
  2937.  
  2938.  
  2939. /*****************************************************************************
  2940. *
  2941. * FUNCTION
  2942. *
  2943. *   filter_shadow_ray
  2944. *
  2945. * INPUT
  2946. *
  2947. * OUTPUT
  2948. *
  2949. * RETURNS
  2950. *
  2951. * AUTHOR
  2952. *
  2953. *   POV-Ray Team
  2954. *
  2955. * DESCRIPTION
  2956. *
  2957. *   -
  2958. *
  2959. * CHANGES
  2960. *
  2961. *   Aug 1994 : Code for early exit due to opaque object added. [DB]
  2962. *
  2963. *   Sep 1994 : Code for multi-textured blobs added. [DB]
  2964. *
  2965. *   May 1995 : Added caustic code by Steve Anger. [DB]
  2966. *
  2967. *   Aug 1995 : Added code to attenuate light source color
  2968. *              due to atmospheric effects. [DB]
  2969. *
  2970. ******************************************************************************/
  2971.  
  2972. static void filter_shadow_ray(Ray_Intersection, Light_Source_Ray, Colour)
  2973. INTERSECTION *Ray_Intersection;
  2974. RAY *Light_Source_Ray;
  2975. COLOUR Colour;
  2976. {
  2977.   int i, Texture_Count;
  2978.   VECTOR IPoint;
  2979.   VECTOR Raw_Normal;
  2980.   COLOUR FC1, Temp_Colour;
  2981.   TEXTURE *Texture = NULL;  /* To remove uninitialized use warning [AED] */
  2982.  
  2983.   Assign_Vector(IPoint, Ray_Intersection->IPoint);
  2984.  
  2985.   if (!(opts.Quality_Flags & Q_SHADOW))
  2986.   {
  2987.     return;
  2988.   }
  2989.  
  2990.   /* If the object is opaque there's no need to go any further. [DB 8/94] */
  2991.  
  2992.   if (Test_Flag(Ray_Intersection->Object, OPAQUE_FLAG))
  2993.   {
  2994.     Make_Colour(Colour, 0.0, 0.0, 0.0);
  2995.  
  2996.     return;
  2997.   }
  2998.  
  2999.   /* Get the normal to the surface */
  3000.  
  3001.   Normal(Raw_Normal, Ray_Intersection->Object, Ray_Intersection);
  3002.  
  3003.   /* Get texture list and weights. */
  3004.  
  3005.   Texture_Count = create_texture_list(Ray_Intersection);
  3006.  
  3007.   Make_ColourA(Temp_Colour, 0.0, 0.0, 0.0, 0.0, 0.0);
  3008.  
  3009.   for (i = 0; i < Texture_Count; i++)
  3010.   {
  3011.     /* If contribution of this texture is neglectable skip ahead. */
  3012.  
  3013.     if (Weight_List[i] < BLACK_LEVEL)
  3014.     {
  3015.       continue;
  3016.     }
  3017.  
  3018.     Texture = Texture_List[i];
  3019.  
  3020.     do_texture_map(FC1, Texture, IPoint, Raw_Normal, Light_Source_Ray, 0.0, Ray_Intersection, TRUE);
  3021.  
  3022.     Temp_Colour[RED]     += Weight_List[i] * FC1[RED];
  3023.     Temp_Colour[GREEN]   += Weight_List[i] * FC1[GREEN];
  3024.     Temp_Colour[BLUE]    += Weight_List[i] * FC1[BLUE];
  3025.     Temp_Colour[FILTER]  += Weight_List[i] * FC1[FILTER];
  3026.     Temp_Colour[TRANSM]  += Weight_List[i] * FC1[TRANSM];
  3027.   }
  3028.  
  3029.   if (fabs(Temp_Colour[FILTER]) + fabs(Temp_Colour[TRANSM]) < BLACK_LEVEL)
  3030.   {
  3031.     Make_Colour(Colour, 0.0, 0.0, 0.0);
  3032.   }
  3033.   else
  3034.   {
  3035.     Colour[RED]   *= Temp_Colour[FILTER] * Temp_Colour[RED]  + Temp_Colour[TRANSM];
  3036.     Colour[GREEN] *= Temp_Colour[FILTER] * Temp_Colour[GREEN]+ Temp_Colour[TRANSM];
  3037.     Colour[BLUE]  *= Temp_Colour[FILTER] * Temp_Colour[BLUE] + Temp_Colour[TRANSM];
  3038.   }
  3039.  
  3040.   /* Get atmospheric attenuation. */
  3041.  
  3042.   do_light_ray_atmosphere(Light_Source_Ray, Ray_Intersection, Texture, Colour, TRUE);
  3043. }
  3044.  
  3045.  
  3046.  
  3047. /*****************************************************************************
  3048. *
  3049. * FUNCTION
  3050. *
  3051. *   do_blocking
  3052. *
  3053. * INPUT
  3054. *
  3055. * OUTPUT
  3056. *
  3057. * RETURNS
  3058. *
  3059. * AUTHOR
  3060. *
  3061. *   POV-Ray Team
  3062. *
  3063. * DESCRIPTION
  3064. *
  3065. *   -
  3066. *
  3067. * CHANGES
  3068. *
  3069. *   -
  3070. *
  3071. ******************************************************************************/
  3072.  
  3073. static int do_blocking(Local_Intersection, Light_Source_Ray, Light_Colour, Local_Stack)
  3074. INTERSECTION *Local_Intersection;
  3075. RAY *Light_Source_Ray;
  3076. COLOUR Light_Colour;
  3077. ISTACK *Local_Stack;
  3078. {
  3079.   Increase_Counter(stats[Shadow_Rays_Succeeded]);
  3080.  
  3081.   filter_shadow_ray(Local_Intersection, Light_Source_Ray, Light_Colour);
  3082.  
  3083.   if ((fabs(Light_Colour[RED])   < BLACK_LEVEL) &&
  3084.       (fabs(Light_Colour[GREEN]) < BLACK_LEVEL) &&
  3085.       (fabs(Light_Colour[BLUE])  < BLACK_LEVEL))
  3086.   {
  3087.     while ((Local_Intersection = pop_entry(Local_Stack)) != NULL)
  3088.     {
  3089.     }
  3090.  
  3091.     return(TRUE);
  3092.   }
  3093.  
  3094.   return(FALSE);
  3095. }
  3096.  
  3097.  
  3098.  
  3099. /*****************************************************************************
  3100. *
  3101. * FUNCTION
  3102. *
  3103. *   block_light_source
  3104. *
  3105. * INPUT
  3106. *
  3107. *   Light            - Light source
  3108. *   Depth            - Distance to light source
  3109. *   Light_Source_Ray - Light ray
  3110. *   Eye_Ray          - Ray from eye to current intersection point
  3111. *   P                - Surface point to shade
  3112. *
  3113. * OUTPUT
  3114. *
  3115. *   Colour           - Light color reaching point P
  3116. *
  3117. * RETURNS
  3118. *
  3119. * AUTHOR
  3120. *
  3121. *   Dieter Bayer
  3122. *
  3123. * DESCRIPTION
  3124. *
  3125. *   Determine how much light from the given light source reaches
  3126. *   the given point. This includes attenuation due to blocking
  3127. *   and translucent objects and atmospheric effects.
  3128. *
  3129. * CHANGES
  3130. *
  3131. *   Jan 1995 : Creation (Extracted from common code).
  3132. *
  3133. *   Aug 1995 : Added code to support atmospheric effects. [DB]
  3134. *
  3135. ******************************************************************************/
  3136.  
  3137. static void block_light_source(Light, Depth, Light_Source_Ray, Eye_Ray, P, Colour)
  3138. LIGHT_SOURCE *Light;
  3139. DBL Depth;
  3140. RAY *Light_Source_Ray, *Eye_Ray;
  3141. VECTOR P;
  3142. COLOUR Colour;
  3143. {
  3144.   DBL New_Depth;
  3145.   INTERSECTION Intersection;
  3146.   RAY New_Ray;
  3147.  
  3148.   /* Store current depth and ray because they will be modified. */
  3149.  
  3150.   New_Depth = Depth;
  3151.  
  3152.   New_Ray = *Light_Source_Ray;
  3153.  
  3154.   /* Get shadows from current light source. */
  3155.  
  3156.   if ((Light->Area_Light) && (opts.Quality_Flags & Q_AREA_LIGHT))
  3157.   {
  3158.     block_area_light(Light, &New_Depth, &New_Ray, Eye_Ray, P, Colour, 0, 0, 0, 0, 0);
  3159.   }
  3160.   else
  3161.   {
  3162.     if (opts.Options & USE_LIGHT_BUFFER)
  3163.     {
  3164.       block_point_light_LBuffer(Light, &New_Depth, &New_Ray, Colour);
  3165.     }
  3166.     else
  3167.     {
  3168.       block_point_light(Light, &New_Depth, &New_Ray, Colour);
  3169.     }
  3170.   }
  3171.  
  3172.   /*
  3173.    * If there's some distance left for the ray to reach the light source
  3174.    * we have to apply atmospheric stuff to this part of the ray.
  3175.    */
  3176.  
  3177.   if ((New_Depth > SHADOW_TOLERANCE) &&
  3178.       (Light->Atmosphere_Interaction) &&
  3179.       (Light->Atmospheric_Attenuation))
  3180.   {
  3181.     Intersection.Depth = New_Depth;
  3182.  
  3183.     do_light_ray_atmosphere(&New_Ray, &Intersection, NULL, Colour, FALSE);
  3184.   }
  3185. }
  3186.  
  3187.  
  3188.  
  3189. /*****************************************************************************
  3190. *
  3191. * FUNCTION
  3192. *
  3193. *   average_textures
  3194. *
  3195. * INPUT
  3196. *
  3197. * OUTPUT
  3198. *
  3199. * RETURNS
  3200. *
  3201. * AUTHOR
  3202. *
  3203. *   POV-Ray Team
  3204. *
  3205. * DESCRIPTION
  3206. *
  3207. *   -
  3208. *
  3209. * CHANGES
  3210. *
  3211. *   -
  3212. *
  3213. ******************************************************************************/
  3214.  
  3215. static void average_textures (Result_Colour, Texture, IPoint, Raw_Normal,
  3216.   Ray, Weight, Ray_Intersection, Shadow_Flag)
  3217. COLOUR Result_Colour;
  3218. TEXTURE *Texture;
  3219. VECTOR IPoint, Raw_Normal;
  3220. RAY *Ray;
  3221. DBL Weight;
  3222. INTERSECTION *Ray_Intersection;
  3223. int Shadow_Flag;
  3224. {
  3225.    int i;
  3226.    COLOUR LC;
  3227.    BLEND_MAP *Map = Texture->Blend_Map;
  3228.    SNGL Value;
  3229.    SNGL Total = 0.0;
  3230.  
  3231.    Make_Colour (Result_Colour, 0.0, 0.0, 0.0);
  3232.  
  3233.    for (i = 0; i < Map->Number_Of_Entries; i++)
  3234.    {
  3235.      Value = Map->Blend_Map_Entries[i].value;
  3236.  
  3237.      do_texture_map (LC,Map->Blend_Map_Entries[i].Vals.Texture, IPoint,Raw_Normal,Ray,Weight,Ray_Intersection,Shadow_Flag);
  3238.  
  3239.      Result_Colour[RED]   += LC[RED]   *Value;
  3240.      Result_Colour[GREEN] += LC[GREEN] *Value;
  3241.      Result_Colour[BLUE]  += LC[BLUE]  *Value;
  3242.      Result_Colour[FILTER]+= LC[FILTER]*Value;
  3243.      Result_Colour[TRANSM]+= LC[TRANSM]*Value;
  3244.  
  3245.      Total += Value;
  3246.    }
  3247.  
  3248.    Result_Colour[RED]   /= Total;
  3249.    Result_Colour[GREEN] /= Total;
  3250.    Result_Colour[BLUE]  /= Total;
  3251.    Result_Colour[FILTER]/= Total;
  3252.    Result_Colour[TRANSM]/= Total;
  3253. }
  3254.  
  3255.  
  3256.  
  3257. /*****************************************************************************
  3258. *
  3259. * FUNCTION
  3260. *
  3261. *   do_light_ray_atmosphere
  3262. *
  3263. * INPUT
  3264. *
  3265. *   Light_Source_Ray - Current ray towards light source
  3266. *   Ray_Intersection - Current intersection with a blocking object
  3267. *   Texture          - Current PNFH texture
  3268. *   Valid_Object     - Flag: 1=a valid object is in the intersection struct
  3269. *
  3270. * OUTPUT
  3271. *
  3272. *   Colour           - Attenuated light source color
  3273. *
  3274. * RETURNS
  3275. *
  3276. * AUTHOR
  3277. *
  3278. *   Dieter Bayer
  3279. *
  3280. * DESCRIPTION
  3281. *
  3282. *   Determine the influence of atmospheric effects on a light source ray.
  3283. *
  3284. * CHANGES
  3285. *
  3286. *   Aug 1995 : Creation.
  3287. *
  3288. ******************************************************************************/
  3289.  
  3290. static void do_light_ray_atmosphere(Light_Source_Ray, Ray_Intersection, Texture, Colour, Valid_Object)
  3291. RAY *Light_Source_Ray;
  3292. INTERSECTION *Ray_Intersection;
  3293. TEXTURE *Texture;
  3294. COLOUR Colour;
  3295. int Valid_Object;
  3296. {
  3297.   int texture_nr;
  3298.   int i, all_hollow;
  3299.  
  3300.   /* Why are we here? */
  3301.  
  3302.   if ((Colour[RED] < BLACK_LEVEL) && (Colour[GREEN] < BLACK_LEVEL) && (Colour[BLUE] < BLACK_LEVEL))
  3303.   {
  3304.     return;
  3305.   }
  3306.  
  3307.   all_hollow = TRUE;
  3308.  
  3309.   for (i = 0; i <= Light_Source_Ray->Containing_Index; i++)
  3310.   {
  3311.     if (!Test_Flag(Light_Source_Ray->Containing_Objects[i], HOLLOW_FLAG))
  3312.     {
  3313.       all_hollow = FALSE;
  3314.  
  3315.       break;
  3316.     }
  3317.   }
  3318.  
  3319.   /* Apply atmospheric effects inside and/or outside any object. */
  3320.  
  3321.   if (all_hollow || (Valid_Object && Test_Flag(Ray_Intersection->Object, HOLLOW_FLAG)))
  3322.   {
  3323.     Do_Finite_Atmosphere(Light_Source_Ray, Ray_Intersection, Colour, TRUE);
  3324.   }
  3325.  
  3326.   /* Handle contained textures. */
  3327.  
  3328.   if (Valid_Object)
  3329.   {
  3330.     if (Light_Source_Ray->Containing_Index == -1)
  3331.     {
  3332.       /* The ray is entering from the atmosphere */
  3333.  
  3334.       Ray_Enter(Light_Source_Ray, Texture, Ray_Intersection->Object);
  3335.     }
  3336.     else
  3337.     {
  3338.       /* The ray is currently inside an object */
  3339.  
  3340.       if ((texture_nr = Texture_In_Ray_Container(Light_Source_Ray, Texture)) >= 0)
  3341.       {
  3342.         /* The ray is leaving the current object */
  3343.  
  3344.         Ray_Exit(Light_Source_Ray, texture_nr);
  3345.       }
  3346.       else
  3347.       {
  3348.         /* The ray is entering a new object */
  3349.  
  3350.         Ray_Enter(Light_Source_Ray, Texture, Ray_Intersection->Object);
  3351.       }
  3352.     }
  3353.   }
  3354. }
  3355.